| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Driver for the MaxLinear MxL69x family of combo tuners/demods
- *
- * Copyright (C) 2020 Brad Love <brad@nextdimension.cc>
- *
- * based on code:
- * Copyright (c) 2016 MaxLinear, Inc. All rights reserved
- * which was released under GPL V2
- */
- #include <linux/mutex.h>
- #include <linux/i2c-mux.h>
- #include <linux/string.h>
- #include <linux/firmware.h>
- #include "mxl692.h"
- #include "mxl692_defs.h"
- static const struct dvb_frontend_ops mxl692_ops;
- struct mxl692_dev {
- struct dvb_frontend fe;
- struct i2c_client *i2c_client;
- struct mutex i2c_lock; /* i2c command mutex */
- enum MXL_EAGLE_DEMOD_TYPE_E demod_type;
- enum MXL_EAGLE_POWER_MODE_E power_mode;
- u32 current_frequency;
- int device_type;
- int seqnum;
- int init_done;
- };
- static int mxl692_i2c_write(struct mxl692_dev *dev, u8 *buffer, u16 buf_len)
- {
- int ret = 0;
- struct i2c_msg msg = {
- .addr = dev->i2c_client->addr,
- .flags = 0,
- .buf = buffer,
- .len = buf_len
- };
- ret = i2c_transfer(dev->i2c_client->adapter, &msg, 1);
- if (ret != 1)
- dev_dbg(&dev->i2c_client->dev, "i2c write error!\n");
- return ret;
- }
- static int mxl692_i2c_read(struct mxl692_dev *dev, u8 *buffer, u16 buf_len)
- {
- int ret = 0;
- struct i2c_msg msg = {
- .addr = dev->i2c_client->addr,
- .flags = I2C_M_RD,
- .buf = buffer,
- .len = buf_len
- };
- ret = i2c_transfer(dev->i2c_client->adapter, &msg, 1);
- if (ret != 1)
- dev_dbg(&dev->i2c_client->dev, "i2c read error!\n");
- return ret;
- }
- static int convert_endian(u32 size, u8 *d)
- {
- u32 i;
- for (i = 0; i < (size & ~3); i += 4) {
- d[i + 0] ^= d[i + 3];
- d[i + 3] ^= d[i + 0];
- d[i + 0] ^= d[i + 3];
- d[i + 1] ^= d[i + 2];
- d[i + 2] ^= d[i + 1];
- d[i + 1] ^= d[i + 2];
- }
- switch (size & 3) {
- case 0:
- case 1:
- /* do nothing */
- break;
- case 2:
- d[i + 0] ^= d[i + 1];
- d[i + 1] ^= d[i + 0];
- d[i + 0] ^= d[i + 1];
- break;
- case 3:
- d[i + 0] ^= d[i + 2];
- d[i + 2] ^= d[i + 0];
- d[i + 0] ^= d[i + 2];
- break;
- }
- return size;
- }
- static int convert_endian_n(int n, u32 size, u8 *d)
- {
- int i, count = 0;
- for (i = 0; i < n; i += size)
- count += convert_endian(size, d + i);
- return count;
- }
- static void mxl692_tx_swap(enum MXL_EAGLE_OPCODE_E opcode, u8 *buffer)
- {
- #ifdef __BIG_ENDIAN
- return;
- #endif
- buffer += MXL_EAGLE_HOST_MSG_HEADER_SIZE; /* skip API header */
- switch (opcode) {
- case MXL_EAGLE_OPCODE_DEVICE_INTR_MASK_SET:
- case MXL_EAGLE_OPCODE_TUNER_CHANNEL_TUNE_SET:
- case MXL_EAGLE_OPCODE_SMA_TRANSMIT_SET:
- buffer += convert_endian(sizeof(u32), buffer);
- break;
- case MXL_EAGLE_OPCODE_QAM_PARAMS_SET:
- buffer += 5;
- buffer += convert_endian(2 * sizeof(u32), buffer);
- break;
- default:
- /* no swapping - all get opcodes */
- /* ATSC/OOB no swapping */
- break;
- }
- }
- static void mxl692_rx_swap(enum MXL_EAGLE_OPCODE_E opcode, u8 *buffer)
- {
- #ifdef __BIG_ENDIAN
- return;
- #endif
- buffer += MXL_EAGLE_HOST_MSG_HEADER_SIZE; /* skip API header */
- switch (opcode) {
- case MXL_EAGLE_OPCODE_TUNER_AGC_STATUS_GET:
- buffer++;
- buffer += convert_endian(2 * sizeof(u16), buffer);
- break;
- case MXL_EAGLE_OPCODE_ATSC_STATUS_GET:
- buffer += convert_endian_n(2, sizeof(u16), buffer);
- buffer += convert_endian(sizeof(u32), buffer);
- break;
- case MXL_EAGLE_OPCODE_ATSC_ERROR_COUNTERS_GET:
- buffer += convert_endian(3 * sizeof(u32), buffer);
- break;
- case MXL_EAGLE_OPCODE_ATSC_EQUALIZER_FILTER_FFE_TAPS_GET:
- buffer += convert_endian_n(24, sizeof(u16), buffer);
- break;
- case MXL_EAGLE_OPCODE_QAM_STATUS_GET:
- buffer += 8;
- buffer += convert_endian_n(2, sizeof(u16), buffer);
- buffer += convert_endian(sizeof(u32), buffer);
- break;
- case MXL_EAGLE_OPCODE_QAM_ERROR_COUNTERS_GET:
- buffer += convert_endian(7 * sizeof(u32), buffer);
- break;
- case MXL_EAGLE_OPCODE_QAM_CONSTELLATION_VALUE_GET:
- case MXL_EAGLE_OPCODE_QAM_EQUALIZER_FILTER_DFE_START_GET:
- case MXL_EAGLE_OPCODE_QAM_EQUALIZER_FILTER_DFE_MIDDLE_GET:
- case MXL_EAGLE_OPCODE_QAM_EQUALIZER_FILTER_DFE_END_GET:
- case MXL_EAGLE_OPCODE_QAM_EQUALIZER_FILTER_SPUR_START_GET:
- buffer += convert_endian_n(24, sizeof(u16), buffer);
- break;
- case MXL_EAGLE_OPCODE_QAM_EQUALIZER_FILTER_SPUR_END_GET:
- buffer += convert_endian_n(8, sizeof(u16), buffer);
- break;
- case MXL_EAGLE_OPCODE_QAM_EQUALIZER_FILTER_FFE_GET:
- buffer += convert_endian_n(17, sizeof(u16), buffer);
- break;
- case MXL_EAGLE_OPCODE_OOB_ERROR_COUNTERS_GET:
- buffer += convert_endian(3 * sizeof(u32), buffer);
- break;
- case MXL_EAGLE_OPCODE_OOB_STATUS_GET:
- buffer += convert_endian_n(2, sizeof(u16), buffer);
- buffer += convert_endian(sizeof(u32), buffer);
- break;
- case MXL_EAGLE_OPCODE_SMA_RECEIVE_GET:
- buffer += convert_endian(sizeof(u32), buffer);
- break;
- default:
- /* no swapping - all set opcodes */
- break;
- }
- }
- static u32 mxl692_checksum(u8 *buffer, u32 size)
- {
- u32 ix, div_size;
- u32 cur_cksum = 0;
- __be32 *buf;
- div_size = DIV_ROUND_UP(size, 4);
- buf = (__be32 *)buffer;
- for (ix = 0; ix < div_size; ix++)
- cur_cksum += be32_to_cpu(buf[ix]);
- cur_cksum ^= 0xDEADBEEF;
- return cur_cksum;
- }
- static int mxl692_validate_fw_header(struct mxl692_dev *dev,
- const u8 *buffer, u32 buf_len)
- {
- int status = 0;
- u32 ix, temp;
- __be32 *local_buf = NULL;
- u8 temp_cksum = 0;
- static const u8 fw_hdr[] = {
- 0x4D, 0x31, 0x10, 0x02, 0x40, 0x00, 0x00, 0x80
- };
- if (memcmp(buffer, fw_hdr, 8) != 0) {
- status = -EINVAL;
- goto err_finish;
- }
- local_buf = (__be32 *)(buffer + 8);
- temp = be32_to_cpu(*local_buf);
- if ((buf_len - 16) != temp >> 8) {
- status = -EINVAL;
- goto err_finish;
- }
- for (ix = 16; ix < buf_len; ix++)
- temp_cksum += buffer[ix];
- if (temp_cksum != buffer[11])
- status = -EINVAL;
- err_finish:
- if (status)
- dev_dbg(&dev->i2c_client->dev, "failed\n");
- return status;
- }
- static int mxl692_write_fw_block(struct mxl692_dev *dev, const u8 *buffer,
- u32 buf_len, u32 *index)
- {
- int status = 0;
- u32 ix = 0, total_len = 0, addr = 0, chunk_len = 0, prevchunk_len = 0;
- u8 local_buf[MXL_EAGLE_MAX_I2C_PACKET_SIZE] = {}, *plocal_buf = NULL;
- int payload_max = MXL_EAGLE_MAX_I2C_PACKET_SIZE - MXL_EAGLE_I2C_MHEADER_SIZE;
- ix = *index;
- if (buffer[ix] == 0x53) {
- total_len = buffer[ix + 1] << 16 | buffer[ix + 2] << 8 | buffer[ix + 3];
- total_len = (total_len + 3) & ~3;
- addr = buffer[ix + 4] << 24 | buffer[ix + 5] << 16 |
- buffer[ix + 6] << 8 | buffer[ix + 7];
- ix += MXL_EAGLE_FW_SEGMENT_HEADER_SIZE;
- while ((total_len > 0) && (status == 0)) {
- plocal_buf = local_buf;
- chunk_len = (total_len < payload_max) ? total_len : payload_max;
- *plocal_buf++ = 0xFC;
- *plocal_buf++ = chunk_len + sizeof(u32);
- *(u32 *)plocal_buf = addr + prevchunk_len;
- #ifdef __BIG_ENDIAN
- convert_endian(sizeof(u32), plocal_buf);
- #endif
- plocal_buf += sizeof(u32);
- memcpy(plocal_buf, &buffer[ix], chunk_len);
- convert_endian(chunk_len, plocal_buf);
- if (mxl692_i2c_write(dev, local_buf,
- (chunk_len + MXL_EAGLE_I2C_MHEADER_SIZE)) < 0) {
- status = -EREMOTEIO;
- break;
- }
- prevchunk_len += chunk_len;
- total_len -= chunk_len;
- ix += chunk_len;
- }
- *index = ix;
- } else {
- status = -EINVAL;
- }
- if (status)
- dev_dbg(&dev->i2c_client->dev, "err %d\n", status);
- return status;
- }
- static int mxl692_memwrite(struct mxl692_dev *dev, u32 addr,
- u8 *buffer, u32 size)
- {
- int status = 0, total_len = 0;
- u8 local_buf[MXL_EAGLE_MAX_I2C_PACKET_SIZE] = {}, *plocal_buf = NULL;
- total_len = size;
- total_len = (total_len + 3) & ~3; /* 4 byte alignment */
- if (total_len > (MXL_EAGLE_MAX_I2C_PACKET_SIZE - MXL_EAGLE_I2C_MHEADER_SIZE))
- dev_dbg(&dev->i2c_client->dev, "hrmph?\n");
- plocal_buf = local_buf;
- *plocal_buf++ = 0xFC;
- *plocal_buf++ = total_len + sizeof(u32);
- *(u32 *)plocal_buf = addr;
- plocal_buf += sizeof(u32);
- memcpy(plocal_buf, buffer, total_len);
- #ifdef __BIG_ENDIAN
- convert_endian(sizeof(u32) + total_len, local_buf + 2);
- #endif
- if (mxl692_i2c_write(dev, local_buf,
- (total_len + MXL_EAGLE_I2C_MHEADER_SIZE)) < 0) {
- status = -EREMOTEIO;
- goto err_finish;
- }
- return status;
- err_finish:
- dev_dbg(&dev->i2c_client->dev, "err %d\n", status);
- return status;
- }
- static int mxl692_memread(struct mxl692_dev *dev, u32 addr,
- u8 *buffer, u32 size)
- {
- int status = 0;
- u8 local_buf[MXL_EAGLE_I2C_MHEADER_SIZE] = {}, *plocal_buf = NULL;
- plocal_buf = local_buf;
- *plocal_buf++ = 0xFB;
- *plocal_buf++ = sizeof(u32);
- *(u32 *)plocal_buf = addr;
- #ifdef __BIG_ENDIAN
- convert_endian(sizeof(u32), plocal_buf);
- #endif
- mutex_lock(&dev->i2c_lock);
- if (mxl692_i2c_write(dev, local_buf, MXL_EAGLE_I2C_MHEADER_SIZE) > 0) {
- size = (size + 3) & ~3; /* 4 byte alignment */
- status = mxl692_i2c_read(dev, buffer, (u16)size) < 0 ? -EREMOTEIO : 0;
- #ifdef __BIG_ENDIAN
- if (status == 0)
- convert_endian(size, buffer);
- #endif
- } else {
- status = -EREMOTEIO;
- }
- mutex_unlock(&dev->i2c_lock);
- if (status)
- dev_dbg(&dev->i2c_client->dev, "err %d\n", status);
- return status;
- }
- static const char *mxl692_opcode_string(u8 opcode)
- {
- if (opcode <= MXL_EAGLE_OPCODE_INTERNAL)
- return MXL_EAGLE_OPCODE_STRING[opcode];
- return "invalid opcode";
- }
- static int mxl692_opwrite(struct mxl692_dev *dev, u8 *buffer,
- u32 size)
- {
- int status = 0, total_len = 0;
- u8 local_buf[MXL_EAGLE_MAX_I2C_PACKET_SIZE] = {}, *plocal_buf = NULL;
- struct MXL_EAGLE_HOST_MSG_HEADER_T *tx_hdr = (struct MXL_EAGLE_HOST_MSG_HEADER_T *)buffer;
- total_len = size;
- total_len = (total_len + 3) & ~3; /* 4 byte alignment */
- if (total_len > (MXL_EAGLE_MAX_I2C_PACKET_SIZE - MXL_EAGLE_I2C_PHEADER_SIZE))
- dev_dbg(&dev->i2c_client->dev, "hrmph?\n");
- plocal_buf = local_buf;
- *plocal_buf++ = 0xFE;
- *plocal_buf++ = (u8)total_len;
- memcpy(plocal_buf, buffer, total_len);
- convert_endian(total_len, plocal_buf);
- if (mxl692_i2c_write(dev, local_buf,
- (total_len + MXL_EAGLE_I2C_PHEADER_SIZE)) < 0) {
- status = -EREMOTEIO;
- goto err_finish;
- }
- err_finish:
- if (status)
- dev_dbg(&dev->i2c_client->dev, "opcode %s err %d\n",
- mxl692_opcode_string(tx_hdr->opcode), status);
- return status;
- }
- static int mxl692_opread(struct mxl692_dev *dev, u8 *buffer,
- u32 size)
- {
- int status = 0;
- u32 ix = 0;
- u8 local_buf[MXL_EAGLE_I2C_PHEADER_SIZE] = {};
- local_buf[0] = 0xFD;
- local_buf[1] = 0;
- if (mxl692_i2c_write(dev, local_buf, MXL_EAGLE_I2C_PHEADER_SIZE) > 0) {
- size = (size + 3) & ~3; /* 4 byte alignment */
- /* Read in 4 byte chunks */
- for (ix = 0; ix < size; ix += 4) {
- if (mxl692_i2c_read(dev, buffer + ix, 4) < 0) {
- dev_dbg(&dev->i2c_client->dev, "ix=%d size=%d\n", ix, size);
- status = -EREMOTEIO;
- goto err_finish;
- }
- }
- convert_endian(size, buffer);
- } else {
- status = -EREMOTEIO;
- }
- err_finish:
- if (status)
- dev_dbg(&dev->i2c_client->dev, "err %d\n", status);
- return status;
- }
- static int mxl692_i2c_writeread(struct mxl692_dev *dev,
- u8 opcode,
- u8 *tx_payload,
- u8 tx_payload_size,
- u8 *rx_payload,
- u8 rx_payload_expected)
- {
- int status = 0, timeout = 40;
- u8 tx_buf[MXL_EAGLE_MAX_I2C_PACKET_SIZE] = {};
- u8 rx_buf[MXL_EAGLE_MAX_I2C_PACKET_SIZE] = {};
- u32 resp_checksum = 0, resp_checksum_tmp = 0;
- struct MXL_EAGLE_HOST_MSG_HEADER_T *tx_header;
- struct MXL_EAGLE_HOST_MSG_HEADER_T *rx_header;
- mutex_lock(&dev->i2c_lock);
- if ((tx_payload_size + MXL_EAGLE_HOST_MSG_HEADER_SIZE) >
- (MXL_EAGLE_MAX_I2C_PACKET_SIZE - MXL_EAGLE_I2C_PHEADER_SIZE)) {
- status = -EINVAL;
- goto err_finish;
- }
- tx_header = (struct MXL_EAGLE_HOST_MSG_HEADER_T *)tx_buf;
- tx_header->opcode = opcode;
- tx_header->seqnum = dev->seqnum++;
- tx_header->payload_size = tx_payload_size;
- tx_header->checksum = 0;
- if (dev->seqnum == 0)
- dev->seqnum = 1;
- if (tx_payload && tx_payload_size > 0)
- memcpy(&tx_buf[MXL_EAGLE_HOST_MSG_HEADER_SIZE], tx_payload, tx_payload_size);
- mxl692_tx_swap(opcode, tx_buf);
- tx_header->checksum = 0;
- tx_header->checksum = mxl692_checksum(tx_buf,
- MXL_EAGLE_HOST_MSG_HEADER_SIZE + tx_payload_size);
- #ifdef __LITTLE_ENDIAN
- convert_endian(4, (u8 *)&tx_header->checksum); /* cksum is big endian */
- #endif
- /* send Tx message */
- status = mxl692_opwrite(dev, tx_buf,
- tx_payload_size + MXL_EAGLE_HOST_MSG_HEADER_SIZE);
- if (status) {
- status = -EREMOTEIO;
- goto err_finish;
- }
- /* receive Rx message (polling) */
- rx_header = (struct MXL_EAGLE_HOST_MSG_HEADER_T *)rx_buf;
- do {
- status = mxl692_opread(dev, rx_buf,
- rx_payload_expected + MXL_EAGLE_HOST_MSG_HEADER_SIZE);
- usleep_range(1000, 2000);
- timeout--;
- } while ((timeout > 0) && (status == 0) &&
- (rx_header->seqnum == 0) &&
- (rx_header->checksum == 0));
- if (timeout == 0 || status) {
- dev_dbg(&dev->i2c_client->dev, "timeout=%d status=%d\n",
- timeout, status);
- status = -ETIMEDOUT;
- goto err_finish;
- }
- if (rx_header->status) {
- dev_dbg(&dev->i2c_client->dev, "rx header status code: %d\n", rx_header->status);
- status = -EREMOTEIO;
- goto err_finish;
- }
- if (rx_header->seqnum != tx_header->seqnum ||
- rx_header->opcode != tx_header->opcode ||
- rx_header->payload_size != rx_payload_expected) {
- dev_dbg(&dev->i2c_client->dev, "Something failed seq=%s opcode=%s pSize=%s\n",
- rx_header->seqnum != tx_header->seqnum ? "X" : "0",
- rx_header->opcode != tx_header->opcode ? "X" : "0",
- rx_header->payload_size != rx_payload_expected ? "X" : "0");
- if (rx_header->payload_size != rx_payload_expected)
- dev_dbg(&dev->i2c_client->dev,
- "rx_header->payloadSize=%d rx_payload_expected=%d\n",
- rx_header->payload_size, rx_payload_expected);
- status = -EREMOTEIO;
- goto err_finish;
- }
- resp_checksum = rx_header->checksum;
- rx_header->checksum = 0;
- resp_checksum_tmp = mxl692_checksum(rx_buf,
- MXL_EAGLE_HOST_MSG_HEADER_SIZE + rx_header->payload_size);
- #ifdef __LITTLE_ENDIAN
- convert_endian(4, (u8 *)&resp_checksum_tmp); /* cksum is big endian */
- #endif
- if (resp_checksum != resp_checksum_tmp) {
- dev_dbg(&dev->i2c_client->dev, "rx checksum failure\n");
- status = -EREMOTEIO;
- goto err_finish;
- }
- mxl692_rx_swap(rx_header->opcode, rx_buf);
- if (rx_header->payload_size > 0) {
- if (!rx_payload) {
- dev_dbg(&dev->i2c_client->dev, "no rx payload?!?\n");
- status = -EREMOTEIO;
- goto err_finish;
- }
- memcpy(rx_payload, rx_buf + MXL_EAGLE_HOST_MSG_HEADER_SIZE,
- rx_header->payload_size);
- }
- err_finish:
- if (status)
- dev_dbg(&dev->i2c_client->dev, "err %d\n", status);
- mutex_unlock(&dev->i2c_lock);
- return status;
- }
- static int mxl692_fwdownload(struct mxl692_dev *dev,
- const u8 *firmware_buf, u32 buf_len)
- {
- int status = 0;
- u32 ix, reg_val = 0x1;
- u8 rx_buf[MXL_EAGLE_MAX_I2C_PACKET_SIZE] = {};
- struct MXL_EAGLE_DEV_STATUS_T *dev_status;
- if (buf_len < MXL_EAGLE_FW_HEADER_SIZE ||
- buf_len > MXL_EAGLE_FW_MAX_SIZE_IN_KB * 1000)
- return -EINVAL;
- mutex_lock(&dev->i2c_lock);
- dev_dbg(&dev->i2c_client->dev, "\n");
- status = mxl692_validate_fw_header(dev, firmware_buf, buf_len);
- if (status)
- goto err_finish;
- ix = 16;
- status = mxl692_write_fw_block(dev, firmware_buf, buf_len, &ix); /* DRAM */
- if (status)
- goto err_finish;
- status = mxl692_write_fw_block(dev, firmware_buf, buf_len, &ix); /* IRAM */
- if (status)
- goto err_finish;
- /* release CPU from reset */
- status = mxl692_memwrite(dev, 0x70000018, (u8 *)®_val, sizeof(u32));
- if (status)
- goto err_finish;
- mutex_unlock(&dev->i2c_lock);
- if (status == 0) {
- /* verify FW is alive */
- usleep_range(MXL_EAGLE_FW_LOAD_TIME * 1000, (MXL_EAGLE_FW_LOAD_TIME + 5) * 1000);
- dev_status = (struct MXL_EAGLE_DEV_STATUS_T *)&rx_buf;
- status = mxl692_i2c_writeread(dev,
- MXL_EAGLE_OPCODE_DEVICE_STATUS_GET,
- NULL,
- 0,
- (u8 *)dev_status,
- sizeof(struct MXL_EAGLE_DEV_STATUS_T));
- }
- return status;
- err_finish:
- mutex_unlock(&dev->i2c_lock);
- if (status)
- dev_dbg(&dev->i2c_client->dev, "err %d\n", status);
- return status;
- }
- static int mxl692_get_versions(struct mxl692_dev *dev)
- {
- int status = 0;
- struct MXL_EAGLE_DEV_VER_T dev_ver = {};
- static const char * const chip_id[] = {"N/A", "691", "248", "692"};
- status = mxl692_i2c_writeread(dev, MXL_EAGLE_OPCODE_DEVICE_VERSION_GET,
- NULL,
- 0,
- (u8 *)&dev_ver,
- sizeof(struct MXL_EAGLE_DEV_VER_T));
- if (status)
- return status;
- dev_info(&dev->i2c_client->dev, "MxL692_DEMOD Chip ID: %s\n",
- chip_id[dev_ver.chip_id]);
- dev_info(&dev->i2c_client->dev,
- "MxL692_DEMOD FW Version: %d.%d.%d.%d_RC%d\n",
- dev_ver.firmware_ver[0],
- dev_ver.firmware_ver[1],
- dev_ver.firmware_ver[2],
- dev_ver.firmware_ver[3],
- dev_ver.firmware_ver[4]);
- return status;
- }
- static int mxl692_reset(struct mxl692_dev *dev)
- {
- int status = 0;
- u32 dev_type = MXL_EAGLE_DEVICE_MAX, reg_val = 0x2;
- dev_dbg(&dev->i2c_client->dev, "\n");
- /* legacy i2c override */
- status = mxl692_memwrite(dev, 0x80000100, (u8 *)®_val, sizeof(u32));
- if (status)
- goto err_finish;
- /* verify sku */
- status = mxl692_memread(dev, 0x70000188, (u8 *)&dev_type, sizeof(u32));
- if (status)
- goto err_finish;
- if (dev_type != dev->device_type)
- goto err_finish;
- err_finish:
- if (status)
- dev_dbg(&dev->i2c_client->dev, "err %d\n", status);
- return status;
- }
- static int mxl692_config_regulators(struct mxl692_dev *dev,
- enum MXL_EAGLE_POWER_SUPPLY_SOURCE_E power_supply)
- {
- int status = 0;
- u32 reg_val;
- dev_dbg(&dev->i2c_client->dev, "\n");
- /* configure main regulator according to the power supply source */
- status = mxl692_memread(dev, 0x90000000, (u8 *)®_val, sizeof(u32));
- if (status)
- goto err_finish;
- reg_val &= 0x00FFFFFF;
- reg_val |= (power_supply == MXL_EAGLE_POWER_SUPPLY_SOURCE_SINGLE) ?
- 0x14000000 : 0x10000000;
- status = mxl692_memwrite(dev, 0x90000000, (u8 *)®_val, sizeof(u32));
- if (status)
- goto err_finish;
- /* configure digital regulator to high current mode */
- status = mxl692_memread(dev, 0x90000018, (u8 *)®_val, sizeof(u32));
- if (status)
- goto err_finish;
- reg_val |= 0x800;
- status = mxl692_memwrite(dev, 0x90000018, (u8 *)®_val, sizeof(u32));
- err_finish:
- if (status)
- dev_dbg(&dev->i2c_client->dev, "err %d\n", status);
- return status;
- }
- static int mxl692_config_xtal(struct mxl692_dev *dev,
- struct MXL_EAGLE_DEV_XTAL_T *dev_xtal)
- {
- int status = 0;
- u32 reg_val, reg_val1;
- dev_dbg(&dev->i2c_client->dev, "\n");
- status = mxl692_memread(dev, 0x90000000, (u8 *)®_val, sizeof(u32));
- if (status)
- goto err_finish;
- /* set XTAL capacitance */
- reg_val &= 0xFFFFFFE0;
- reg_val |= dev_xtal->xtal_cap;
- /* set CLK OUT */
- reg_val = dev_xtal->clk_out_enable ? (reg_val | 0x0100) : (reg_val & 0xFFFFFEFF);
- status = mxl692_memwrite(dev, 0x90000000, (u8 *)®_val, sizeof(u32));
- if (status)
- goto err_finish;
- /* set CLK OUT divider */
- reg_val = dev_xtal->clk_out_div_enable ? (reg_val | 0x0200) : (reg_val & 0xFFFFFDFF);
- status = mxl692_memwrite(dev, 0x90000000, (u8 *)®_val, sizeof(u32));
- if (status)
- goto err_finish;
- /* set XTAL sharing */
- reg_val = dev_xtal->xtal_sharing_enable ? (reg_val | 0x010400) : (reg_val & 0xFFFEFBFF);
- status = mxl692_memwrite(dev, 0x90000000, (u8 *)®_val, sizeof(u32));
- if (status)
- goto err_finish;
- /* enable/disable XTAL calibration, based on master/slave device */
- status = mxl692_memread(dev, 0x90000030, (u8 *)®_val1, sizeof(u32));
- if (status)
- goto err_finish;
- if (dev_xtal->xtal_calibration_enable) {
- /* enable XTAL calibration and set XTAL amplitude to a higher value */
- reg_val1 &= 0xFFFFFFFD;
- reg_val1 |= 0x30;
- status = mxl692_memwrite(dev, 0x90000030, (u8 *)®_val1, sizeof(u32));
- if (status)
- goto err_finish;
- } else {
- /* disable XTAL calibration */
- reg_val1 |= 0x2;
- status = mxl692_memwrite(dev, 0x90000030, (u8 *)®_val1, sizeof(u32));
- if (status)
- goto err_finish;
- /* set XTAL bias value */
- status = mxl692_memread(dev, 0x9000002c, (u8 *)®_val, sizeof(u32));
- if (status)
- goto err_finish;
- reg_val &= 0xC0FFFFFF;
- reg_val |= 0xA000000;
- status = mxl692_memwrite(dev, 0x9000002c, (u8 *)®_val, sizeof(u32));
- if (status)
- goto err_finish;
- }
- /* start XTAL calibration */
- status = mxl692_memread(dev, 0x70000010, (u8 *)®_val, sizeof(u32));
- if (status)
- goto err_finish;
- reg_val |= 0x8;
- status = mxl692_memwrite(dev, 0x70000010, (u8 *)®_val, sizeof(u32));
- if (status)
- goto err_finish;
- status = mxl692_memread(dev, 0x70000018, (u8 *)®_val, sizeof(u32));
- if (status)
- goto err_finish;
- reg_val |= 0x10;
- status = mxl692_memwrite(dev, 0x70000018, (u8 *)®_val, sizeof(u32));
- if (status)
- goto err_finish;
- status = mxl692_memread(dev, 0x9001014c, (u8 *)®_val, sizeof(u32));
- if (status)
- goto err_finish;
- reg_val &= 0xFFFFEFFF;
- status = mxl692_memwrite(dev, 0x9001014c, (u8 *)®_val, sizeof(u32));
- if (status)
- goto err_finish;
- reg_val |= 0x1000;
- status = mxl692_memwrite(dev, 0x9001014c, (u8 *)®_val, sizeof(u32));
- if (status)
- goto err_finish;
- usleep_range(45000, 55000);
- err_finish:
- if (status)
- dev_dbg(&dev->i2c_client->dev, "err %d\n", status);
- return status;
- }
- static int mxl692_powermode(struct mxl692_dev *dev,
- enum MXL_EAGLE_POWER_MODE_E power_mode)
- {
- int status = 0;
- u8 mode = power_mode;
- dev_dbg(&dev->i2c_client->dev, "%s\n",
- power_mode == MXL_EAGLE_POWER_MODE_SLEEP ? "sleep" : "active");
- status = mxl692_i2c_writeread(dev,
- MXL_EAGLE_OPCODE_DEVICE_POWERMODE_SET,
- &mode,
- sizeof(u8),
- NULL,
- 0);
- if (status) {
- dev_dbg(&dev->i2c_client->dev, "err %d\n", status);
- return status;
- }
- dev->power_mode = power_mode;
- return status;
- }
- static int mxl692_init(struct dvb_frontend *fe)
- {
- struct mxl692_dev *dev = fe->demodulator_priv;
- struct i2c_client *client = dev->i2c_client;
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- int status = 0;
- const struct firmware *firmware;
- struct MXL_EAGLE_DEV_XTAL_T xtal_config = {};
- dev_dbg(&dev->i2c_client->dev, "\n");
- if (dev->init_done)
- goto warm;
- dev->seqnum = 1;
- status = mxl692_reset(dev);
- if (status)
- goto err;
- usleep_range(50 * 1000, 60 * 1000); /* was 1000! */
- status = mxl692_config_regulators(dev, MXL_EAGLE_POWER_SUPPLY_SOURCE_DUAL);
- if (status)
- goto err;
- xtal_config.xtal_cap = 26;
- xtal_config.clk_out_div_enable = 0;
- xtal_config.clk_out_enable = 0;
- xtal_config.xtal_calibration_enable = 0;
- xtal_config.xtal_sharing_enable = 1;
- status = mxl692_config_xtal(dev, &xtal_config);
- if (status)
- goto err;
- status = request_firmware(&firmware, MXL692_FIRMWARE, &client->dev);
- if (status) {
- dev_dbg(&dev->i2c_client->dev, "firmware missing? %s\n",
- MXL692_FIRMWARE);
- goto err;
- }
- status = mxl692_fwdownload(dev, firmware->data, firmware->size);
- if (status)
- goto err_release_firmware;
- release_firmware(firmware);
- status = mxl692_get_versions(dev);
- if (status)
- goto err;
- dev->power_mode = MXL_EAGLE_POWER_MODE_SLEEP;
- warm:
- /* Config Device Power Mode */
- if (dev->power_mode != MXL_EAGLE_POWER_MODE_ACTIVE) {
- status = mxl692_powermode(dev, MXL_EAGLE_POWER_MODE_ACTIVE);
- if (status)
- goto err;
- usleep_range(50 * 1000, 60 * 1000); /* was 500! */
- }
- /* Init stats here to indicate which stats are supported */
- c->cnr.len = 1;
- c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
- c->post_bit_error.len = 1;
- c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
- c->post_bit_count.len = 1;
- c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
- c->block_error.len = 1;
- c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
- dev->init_done = 1;
- return 0;
- err_release_firmware:
- release_firmware(firmware);
- err:
- dev_dbg(&dev->i2c_client->dev, "err %d\n", status);
- return status;
- }
- static int mxl692_sleep(struct dvb_frontend *fe)
- {
- struct mxl692_dev *dev = fe->demodulator_priv;
- if (dev->power_mode != MXL_EAGLE_POWER_MODE_SLEEP)
- mxl692_powermode(dev, MXL_EAGLE_POWER_MODE_SLEEP);
- return 0;
- }
- static int mxl692_set_frontend(struct dvb_frontend *fe)
- {
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
- struct mxl692_dev *dev = fe->demodulator_priv;
- int status = 0;
- enum MXL_EAGLE_DEMOD_TYPE_E demod_type;
- struct MXL_EAGLE_MPEGOUT_PARAMS_T mpeg_params = {};
- enum MXL_EAGLE_QAM_DEMOD_ANNEX_TYPE_E qam_annex = MXL_EAGLE_QAM_DEMOD_ANNEX_B;
- struct MXL_EAGLE_QAM_DEMOD_PARAMS_T qam_params = {};
- struct MXL_EAGLE_TUNER_CHANNEL_PARAMS_T tuner_params = {};
- u8 op_param = 0;
- dev_dbg(&dev->i2c_client->dev, "\n");
- switch (p->modulation) {
- case VSB_8:
- demod_type = MXL_EAGLE_DEMOD_TYPE_ATSC;
- break;
- case QAM_AUTO:
- case QAM_64:
- case QAM_128:
- case QAM_256:
- demod_type = MXL_EAGLE_DEMOD_TYPE_QAM;
- break;
- default:
- return -EINVAL;
- }
- if (dev->current_frequency == p->frequency && dev->demod_type == demod_type) {
- dev_dbg(&dev->i2c_client->dev, "already set up\n");
- return 0;
- }
- dev->current_frequency = -1;
- dev->demod_type = -1;
- op_param = demod_type;
- status = mxl692_i2c_writeread(dev,
- MXL_EAGLE_OPCODE_DEVICE_DEMODULATOR_TYPE_SET,
- &op_param,
- sizeof(u8),
- NULL,
- 0);
- if (status) {
- dev_dbg(&dev->i2c_client->dev,
- "DEVICE_DEMODULATOR_TYPE_SET...FAIL err 0x%x\n", status);
- goto err;
- }
- usleep_range(20 * 1000, 30 * 1000); /* was 500! */
- mpeg_params.mpeg_parallel = 0;
- mpeg_params.msb_first = MXL_EAGLE_DATA_SERIAL_MSB_1ST;
- mpeg_params.mpeg_sync_pulse_width = MXL_EAGLE_DATA_SYNC_WIDTH_BIT;
- mpeg_params.mpeg_valid_pol = MXL_EAGLE_CLOCK_POSITIVE;
- mpeg_params.mpeg_sync_pol = MXL_EAGLE_CLOCK_POSITIVE;
- mpeg_params.mpeg_clk_pol = MXL_EAGLE_CLOCK_NEGATIVE;
- mpeg_params.mpeg3wire_mode_enable = 0;
- mpeg_params.mpeg_clk_freq = MXL_EAGLE_MPEG_CLOCK_27MHZ;
- switch (demod_type) {
- case MXL_EAGLE_DEMOD_TYPE_ATSC:
- status = mxl692_i2c_writeread(dev,
- MXL_EAGLE_OPCODE_DEVICE_MPEG_OUT_PARAMS_SET,
- (u8 *)&mpeg_params,
- sizeof(struct MXL_EAGLE_MPEGOUT_PARAMS_T),
- NULL,
- 0);
- if (status)
- goto err;
- break;
- case MXL_EAGLE_DEMOD_TYPE_QAM:
- if (qam_annex == MXL_EAGLE_QAM_DEMOD_ANNEX_A)
- mpeg_params.msb_first = MXL_EAGLE_DATA_SERIAL_LSB_1ST;
- status = mxl692_i2c_writeread(dev,
- MXL_EAGLE_OPCODE_DEVICE_MPEG_OUT_PARAMS_SET,
- (u8 *)&mpeg_params,
- sizeof(struct MXL_EAGLE_MPEGOUT_PARAMS_T),
- NULL,
- 0);
- if (status)
- goto err;
- qam_params.annex_type = qam_annex;
- qam_params.qam_type = MXL_EAGLE_QAM_DEMOD_AUTO;
- qam_params.iq_flip = MXL_EAGLE_DEMOD_IQ_AUTO;
- if (p->modulation == QAM_64)
- qam_params.symbol_rate_hz = 5057000;
- else
- qam_params.symbol_rate_hz = 5361000;
- qam_params.symbol_rate_256qam_hz = 5361000;
- status = mxl692_i2c_writeread(dev,
- MXL_EAGLE_OPCODE_QAM_PARAMS_SET,
- (u8 *)&qam_params,
- sizeof(struct MXL_EAGLE_QAM_DEMOD_PARAMS_T),
- NULL, 0);
- if (status)
- goto err;
- break;
- default:
- break;
- }
- usleep_range(20 * 1000, 30 * 1000); /* was 500! */
- tuner_params.freq_hz = p->frequency;
- tuner_params.bandwidth = MXL_EAGLE_TUNER_BW_6MHZ;
- tuner_params.tune_mode = MXL_EAGLE_TUNER_CHANNEL_TUNE_MODE_VIEW;
- dev_dbg(&dev->i2c_client->dev, " Tuning Freq: %d %s\n", tuner_params.freq_hz,
- demod_type == MXL_EAGLE_DEMOD_TYPE_ATSC ? "ATSC" : "QAM");
- status = mxl692_i2c_writeread(dev,
- MXL_EAGLE_OPCODE_TUNER_CHANNEL_TUNE_SET,
- (u8 *)&tuner_params,
- sizeof(struct MXL_EAGLE_TUNER_CHANNEL_PARAMS_T),
- NULL,
- 0);
- if (status)
- goto err;
- usleep_range(20 * 1000, 30 * 1000); /* was 500! */
- switch (demod_type) {
- case MXL_EAGLE_DEMOD_TYPE_ATSC:
- status = mxl692_i2c_writeread(dev,
- MXL_EAGLE_OPCODE_ATSC_INIT_SET,
- NULL, 0, NULL, 0);
- if (status)
- goto err;
- break;
- case MXL_EAGLE_DEMOD_TYPE_QAM:
- status = mxl692_i2c_writeread(dev,
- MXL_EAGLE_OPCODE_QAM_RESTART_SET,
- NULL, 0, NULL, 0);
- if (status)
- goto err;
- break;
- default:
- break;
- }
- dev->demod_type = demod_type;
- dev->current_frequency = p->frequency;
- return 0;
- err:
- dev_dbg(&dev->i2c_client->dev, "err %d\n", status);
- return status;
- }
- static int mxl692_get_frontend(struct dvb_frontend *fe,
- struct dtv_frontend_properties *p)
- {
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- p->modulation = c->modulation;
- p->frequency = c->frequency;
- return 0;
- }
- static int mxl692_read_snr(struct dvb_frontend *fe, u16 *snr)
- {
- struct mxl692_dev *dev = fe->demodulator_priv;
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- u8 rx_buf[MXL_EAGLE_MAX_I2C_PACKET_SIZE] = {};
- struct MXL_EAGLE_ATSC_DEMOD_STATUS_T *atsc_status;
- struct MXL_EAGLE_QAM_DEMOD_STATUS_T *qam_status;
- enum MXL_EAGLE_DEMOD_TYPE_E demod_type = dev->demod_type;
- int mxl_status = 0;
- *snr = 0;
- dev_dbg(&dev->i2c_client->dev, "\n");
- atsc_status = (struct MXL_EAGLE_ATSC_DEMOD_STATUS_T *)&rx_buf;
- qam_status = (struct MXL_EAGLE_QAM_DEMOD_STATUS_T *)&rx_buf;
- switch (demod_type) {
- case MXL_EAGLE_DEMOD_TYPE_ATSC:
- mxl_status = mxl692_i2c_writeread(dev,
- MXL_EAGLE_OPCODE_ATSC_STATUS_GET,
- NULL,
- 0,
- rx_buf,
- sizeof(struct MXL_EAGLE_ATSC_DEMOD_STATUS_T));
- if (!mxl_status) {
- *snr = (u16)(atsc_status->snr_db_tenths / 10);
- c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
- c->cnr.stat[0].svalue = *snr;
- }
- break;
- case MXL_EAGLE_DEMOD_TYPE_QAM:
- mxl_status = mxl692_i2c_writeread(dev,
- MXL_EAGLE_OPCODE_QAM_STATUS_GET,
- NULL,
- 0,
- rx_buf,
- sizeof(struct MXL_EAGLE_QAM_DEMOD_STATUS_T));
- if (!mxl_status)
- *snr = (u16)(qam_status->snr_db_tenths / 10);
- break;
- case MXL_EAGLE_DEMOD_TYPE_OOB:
- default:
- break;
- }
- if (mxl_status)
- dev_dbg(&dev->i2c_client->dev, "err %d\n", mxl_status);
- return mxl_status;
- }
- static int mxl692_read_ber_ucb(struct dvb_frontend *fe)
- {
- struct mxl692_dev *dev = fe->demodulator_priv;
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- u8 rx_buf[MXL_EAGLE_MAX_I2C_PACKET_SIZE] = {};
- struct MXL_EAGLE_ATSC_DEMOD_ERROR_COUNTERS_T *atsc_errors;
- enum MXL_EAGLE_DEMOD_TYPE_E demod_type = dev->demod_type;
- int mxl_status = 0;
- u32 utmp;
- dev_dbg(&dev->i2c_client->dev, "\n");
- atsc_errors = (struct MXL_EAGLE_ATSC_DEMOD_ERROR_COUNTERS_T *)&rx_buf;
- switch (demod_type) {
- case MXL_EAGLE_DEMOD_TYPE_ATSC:
- mxl_status = mxl692_i2c_writeread(dev,
- MXL_EAGLE_OPCODE_ATSC_ERROR_COUNTERS_GET,
- NULL,
- 0,
- rx_buf,
- sizeof(struct MXL_EAGLE_ATSC_DEMOD_ERROR_COUNTERS_T));
- if (!mxl_status) {
- if (atsc_errors->error_packets == 0)
- utmp = 0;
- else
- utmp = ((atsc_errors->error_bytes / atsc_errors->error_packets) *
- atsc_errors->total_packets);
- /* ber */
- c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
- c->post_bit_error.stat[0].uvalue += atsc_errors->error_bytes;
- c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
- c->post_bit_count.stat[0].uvalue += utmp;
- /* ucb */
- c->block_error.stat[0].scale = FE_SCALE_COUNTER;
- c->block_error.stat[0].uvalue += atsc_errors->error_packets;
- dev_dbg(&dev->i2c_client->dev, "%llu %llu\n",
- c->post_bit_count.stat[0].uvalue, c->block_error.stat[0].uvalue);
- }
- break;
- case MXL_EAGLE_DEMOD_TYPE_QAM:
- case MXL_EAGLE_DEMOD_TYPE_OOB:
- default:
- break;
- }
- if (mxl_status)
- dev_dbg(&dev->i2c_client->dev, "err %d\n", mxl_status);
- return mxl_status;
- }
- static int mxl692_read_status(struct dvb_frontend *fe,
- enum fe_status *status)
- {
- struct mxl692_dev *dev = fe->demodulator_priv;
- struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- u8 rx_buf[MXL_EAGLE_MAX_I2C_PACKET_SIZE] = {};
- struct MXL_EAGLE_ATSC_DEMOD_STATUS_T *atsc_status;
- struct MXL_EAGLE_QAM_DEMOD_STATUS_T *qam_status;
- enum MXL_EAGLE_DEMOD_TYPE_E demod_type = dev->demod_type;
- int mxl_status = 0;
- *status = 0;
- dev_dbg(&dev->i2c_client->dev, "\n");
- atsc_status = (struct MXL_EAGLE_ATSC_DEMOD_STATUS_T *)&rx_buf;
- qam_status = (struct MXL_EAGLE_QAM_DEMOD_STATUS_T *)&rx_buf;
- switch (demod_type) {
- case MXL_EAGLE_DEMOD_TYPE_ATSC:
- mxl_status = mxl692_i2c_writeread(dev,
- MXL_EAGLE_OPCODE_ATSC_STATUS_GET,
- NULL,
- 0,
- rx_buf,
- sizeof(struct MXL_EAGLE_ATSC_DEMOD_STATUS_T));
- if (!mxl_status && atsc_status->atsc_lock) {
- *status |= FE_HAS_SIGNAL;
- *status |= FE_HAS_CARRIER;
- *status |= FE_HAS_VITERBI;
- *status |= FE_HAS_SYNC;
- *status |= FE_HAS_LOCK;
- c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
- c->cnr.stat[0].svalue = atsc_status->snr_db_tenths / 10;
- }
- break;
- case MXL_EAGLE_DEMOD_TYPE_QAM:
- mxl_status = mxl692_i2c_writeread(dev,
- MXL_EAGLE_OPCODE_QAM_STATUS_GET,
- NULL,
- 0,
- rx_buf,
- sizeof(struct MXL_EAGLE_QAM_DEMOD_STATUS_T));
- if (!mxl_status && qam_status->qam_locked) {
- *status |= FE_HAS_SIGNAL;
- *status |= FE_HAS_CARRIER;
- *status |= FE_HAS_VITERBI;
- *status |= FE_HAS_SYNC;
- *status |= FE_HAS_LOCK;
- c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
- c->cnr.stat[0].svalue = qam_status->snr_db_tenths / 10;
- }
- break;
- case MXL_EAGLE_DEMOD_TYPE_OOB:
- default:
- break;
- }
- if ((*status & FE_HAS_LOCK) == 0) {
- /* No lock, reset all statistics */
- c->cnr.len = 1;
- c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
- c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
- c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
- c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
- return 0;
- }
- if (mxl_status)
- dev_dbg(&dev->i2c_client->dev, "err %d\n", mxl_status);
- else
- mxl_status = mxl692_read_ber_ucb(fe);
- return mxl_status;
- }
- static const struct dvb_frontend_ops mxl692_ops = {
- .delsys = { SYS_ATSC },
- .info = {
- .name = "MaxLinear MxL692 VSB tuner-demodulator",
- .frequency_min_hz = 54000000,
- .frequency_max_hz = 858000000,
- .frequency_stepsize_hz = 62500,
- .caps = FE_CAN_8VSB
- },
- .init = mxl692_init,
- .sleep = mxl692_sleep,
- .set_frontend = mxl692_set_frontend,
- .get_frontend = mxl692_get_frontend,
- .read_status = mxl692_read_status,
- .read_snr = mxl692_read_snr,
- };
- static int mxl692_probe(struct i2c_client *client)
- {
- struct mxl692_config *config = client->dev.platform_data;
- struct mxl692_dev *dev;
- int ret = 0;
- dev = kzalloc_obj(*dev);
- if (!dev) {
- ret = -ENOMEM;
- dev_dbg(&client->dev, "kzalloc() failed\n");
- goto err;
- }
- memcpy(&dev->fe.ops, &mxl692_ops, sizeof(struct dvb_frontend_ops));
- dev->fe.demodulator_priv = dev;
- dev->i2c_client = client;
- *config->fe = &dev->fe;
- mutex_init(&dev->i2c_lock);
- i2c_set_clientdata(client, dev);
- dev_info(&client->dev, "MaxLinear mxl692 successfully attached\n");
- return 0;
- err:
- dev_dbg(&client->dev, "failed %d\n", ret);
- return -ENODEV;
- }
- static void mxl692_remove(struct i2c_client *client)
- {
- struct mxl692_dev *dev = i2c_get_clientdata(client);
- dev->fe.demodulator_priv = NULL;
- i2c_set_clientdata(client, NULL);
- kfree(dev);
- }
- static const struct i2c_device_id mxl692_id_table[] = {
- { "mxl692" },
- {}
- };
- MODULE_DEVICE_TABLE(i2c, mxl692_id_table);
- static struct i2c_driver mxl692_driver = {
- .driver = {
- .name = "mxl692",
- },
- .probe = mxl692_probe,
- .remove = mxl692_remove,
- .id_table = mxl692_id_table,
- };
- module_i2c_driver(mxl692_driver);
- MODULE_AUTHOR("Brad Love <brad@nextdimension.cc>");
- MODULE_DESCRIPTION("MaxLinear MxL692 demodulator/tuner driver");
- MODULE_FIRMWARE(MXL692_FIRMWARE);
- MODULE_LICENSE("GPL");
|