1dc2b3d17SDaniel Scheller // SPDX-License-Identifier: GPL-2.0 23c4e0415SDaniel Scheller /* 33c4e0415SDaniel Scheller * Driver for the MaxLinear MxL5xx family of tuners/demods 43c4e0415SDaniel Scheller * 53c4e0415SDaniel Scheller * Copyright (C) 2014-2015 Ralph Metzler <rjkm@metzlerbros.de> 63c4e0415SDaniel Scheller * Marcus Metzler <mocm@metzlerbros.de> 73c4e0415SDaniel Scheller * developed for Digital Devices GmbH 83c4e0415SDaniel Scheller * 93c4e0415SDaniel Scheller * based on code: 103c4e0415SDaniel Scheller * Copyright (c) 2011-2013 MaxLinear, Inc. All rights reserved 113c4e0415SDaniel Scheller * which was released under GPL V2 123c4e0415SDaniel Scheller * 133c4e0415SDaniel Scheller * This program is free software; you can redistribute it and/or 143c4e0415SDaniel Scheller * modify it under the terms of the GNU General Public License 153c4e0415SDaniel Scheller * version 2, as published by the Free Software Foundation. 163c4e0415SDaniel Scheller * 173c4e0415SDaniel Scheller * This program is distributed in the hope that it will be useful, 183c4e0415SDaniel Scheller * but WITHOUT ANY WARRANTY; without even the implied warranty of 193c4e0415SDaniel Scheller * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 203c4e0415SDaniel Scheller * GNU General Public License for more details. 213c4e0415SDaniel Scheller */ 223c4e0415SDaniel Scheller 233c4e0415SDaniel Scheller #include <linux/kernel.h> 243c4e0415SDaniel Scheller #include <linux/module.h> 253c4e0415SDaniel Scheller #include <linux/moduleparam.h> 263c4e0415SDaniel Scheller #include <linux/init.h> 273c4e0415SDaniel Scheller #include <linux/delay.h> 283c4e0415SDaniel Scheller #include <linux/firmware.h> 293c4e0415SDaniel Scheller #include <linux/i2c.h> 303c4e0415SDaniel Scheller #include <linux/version.h> 313c4e0415SDaniel Scheller #include <linux/mutex.h> 323c4e0415SDaniel Scheller #include <linux/vmalloc.h> 333c4e0415SDaniel Scheller #include <asm/div64.h> 343c4e0415SDaniel Scheller #include <asm/unaligned.h> 353c4e0415SDaniel Scheller 36fada1935SMauro Carvalho Chehab #include <media/dvb_frontend.h> 373c4e0415SDaniel Scheller #include "mxl5xx.h" 383c4e0415SDaniel Scheller #include "mxl5xx_regs.h" 393c4e0415SDaniel Scheller #include "mxl5xx_defs.h" 403c4e0415SDaniel Scheller 413c4e0415SDaniel Scheller #define BYTE0(v) ((v >> 0) & 0xff) 423c4e0415SDaniel Scheller #define BYTE1(v) ((v >> 8) & 0xff) 433c4e0415SDaniel Scheller #define BYTE2(v) ((v >> 16) & 0xff) 443c4e0415SDaniel Scheller #define BYTE3(v) ((v >> 24) & 0xff) 453c4e0415SDaniel Scheller 46f71c4306SDaniel Scheller static LIST_HEAD(mxllist); 473c4e0415SDaniel Scheller 483c4e0415SDaniel Scheller struct mxl_base { 493c4e0415SDaniel Scheller struct list_head mxllist; 503c4e0415SDaniel Scheller struct list_head mxls; 513c4e0415SDaniel Scheller 523c4e0415SDaniel Scheller u8 adr; 533c4e0415SDaniel Scheller struct i2c_adapter *i2c; 543c4e0415SDaniel Scheller 553c4e0415SDaniel Scheller u32 count; 563c4e0415SDaniel Scheller u32 type; 573c4e0415SDaniel Scheller u32 sku_type; 583c4e0415SDaniel Scheller u32 chipversion; 593c4e0415SDaniel Scheller u32 clock; 603c4e0415SDaniel Scheller u32 fwversion; 613c4e0415SDaniel Scheller 623c4e0415SDaniel Scheller u8 *ts_map; 633c4e0415SDaniel Scheller u8 can_clkout; 643c4e0415SDaniel Scheller u8 chan_bond; 653c4e0415SDaniel Scheller u8 demod_num; 663c4e0415SDaniel Scheller u8 tuner_num; 673c4e0415SDaniel Scheller 683c4e0415SDaniel Scheller unsigned long next_tune; 693c4e0415SDaniel Scheller 703c4e0415SDaniel Scheller struct mutex i2c_lock; 713c4e0415SDaniel Scheller struct mutex status_lock; 723c4e0415SDaniel Scheller struct mutex tune_lock; 733c4e0415SDaniel Scheller 743c4e0415SDaniel Scheller u8 buf[MXL_HYDRA_OEM_MAX_CMD_BUFF_LEN]; 753c4e0415SDaniel Scheller 763c4e0415SDaniel Scheller u32 cmd_size; 773c4e0415SDaniel Scheller u8 cmd_data[MAX_CMD_DATA]; 783c4e0415SDaniel Scheller }; 793c4e0415SDaniel Scheller 803c4e0415SDaniel Scheller struct mxl { 813c4e0415SDaniel Scheller struct list_head mxl; 823c4e0415SDaniel Scheller 833c4e0415SDaniel Scheller struct mxl_base *base; 843c4e0415SDaniel Scheller struct dvb_frontend fe; 853c4e0415SDaniel Scheller struct device *i2cdev; 863c4e0415SDaniel Scheller u32 demod; 873c4e0415SDaniel Scheller u32 tuner; 883c4e0415SDaniel Scheller u32 tuner_in_use; 893c4e0415SDaniel Scheller u8 xbar[3]; 903c4e0415SDaniel Scheller 913c4e0415SDaniel Scheller unsigned long tune_time; 923c4e0415SDaniel Scheller }; 933c4e0415SDaniel Scheller 943c4e0415SDaniel Scheller static void convert_endian(u8 flag, u32 size, u8 *d) 953c4e0415SDaniel Scheller { 963c4e0415SDaniel Scheller u32 i; 973c4e0415SDaniel Scheller 983c4e0415SDaniel Scheller if (!flag) 993c4e0415SDaniel Scheller return; 1003c4e0415SDaniel Scheller for (i = 0; i < (size & ~3); i += 4) { 1013c4e0415SDaniel Scheller d[i + 0] ^= d[i + 3]; 1023c4e0415SDaniel Scheller d[i + 3] ^= d[i + 0]; 1033c4e0415SDaniel Scheller d[i + 0] ^= d[i + 3]; 1043c4e0415SDaniel Scheller 1053c4e0415SDaniel Scheller d[i + 1] ^= d[i + 2]; 1063c4e0415SDaniel Scheller d[i + 2] ^= d[i + 1]; 1073c4e0415SDaniel Scheller d[i + 1] ^= d[i + 2]; 1083c4e0415SDaniel Scheller } 1093c4e0415SDaniel Scheller 1103c4e0415SDaniel Scheller switch (size & 3) { 1113c4e0415SDaniel Scheller case 0: 1123c4e0415SDaniel Scheller case 1: 1133c4e0415SDaniel Scheller /* do nothing */ 1143c4e0415SDaniel Scheller break; 1153c4e0415SDaniel Scheller case 2: 1163c4e0415SDaniel Scheller d[i + 0] ^= d[i + 1]; 1173c4e0415SDaniel Scheller d[i + 1] ^= d[i + 0]; 1183c4e0415SDaniel Scheller d[i + 0] ^= d[i + 1]; 1193c4e0415SDaniel Scheller break; 1203c4e0415SDaniel Scheller 1213c4e0415SDaniel Scheller case 3: 1223c4e0415SDaniel Scheller d[i + 0] ^= d[i + 2]; 1233c4e0415SDaniel Scheller d[i + 2] ^= d[i + 0]; 1243c4e0415SDaniel Scheller d[i + 0] ^= d[i + 2]; 1253c4e0415SDaniel Scheller break; 1263c4e0415SDaniel Scheller } 1273c4e0415SDaniel Scheller 1283c4e0415SDaniel Scheller } 1293c4e0415SDaniel Scheller 1303c4e0415SDaniel Scheller static int i2c_write(struct i2c_adapter *adap, u8 adr, 1313c4e0415SDaniel Scheller u8 *data, u32 len) 1323c4e0415SDaniel Scheller { 1333c4e0415SDaniel Scheller struct i2c_msg msg = {.addr = adr, .flags = 0, 1343c4e0415SDaniel Scheller .buf = data, .len = len}; 1353c4e0415SDaniel Scheller 1363c4e0415SDaniel Scheller return (i2c_transfer(adap, &msg, 1) == 1) ? 0 : -1; 1373c4e0415SDaniel Scheller } 1383c4e0415SDaniel Scheller 1393c4e0415SDaniel Scheller static int i2c_read(struct i2c_adapter *adap, u8 adr, 1403c4e0415SDaniel Scheller u8 *data, u32 len) 1413c4e0415SDaniel Scheller { 1423c4e0415SDaniel Scheller struct i2c_msg msg = {.addr = adr, .flags = I2C_M_RD, 1433c4e0415SDaniel Scheller .buf = data, .len = len}; 1443c4e0415SDaniel Scheller 1453c4e0415SDaniel Scheller return (i2c_transfer(adap, &msg, 1) == 1) ? 0 : -1; 1463c4e0415SDaniel Scheller } 1473c4e0415SDaniel Scheller 1483c4e0415SDaniel Scheller static int i2cread(struct mxl *state, u8 *data, int len) 1493c4e0415SDaniel Scheller { 1503c4e0415SDaniel Scheller return i2c_read(state->base->i2c, state->base->adr, data, len); 1513c4e0415SDaniel Scheller } 1523c4e0415SDaniel Scheller 1533c4e0415SDaniel Scheller static int i2cwrite(struct mxl *state, u8 *data, int len) 1543c4e0415SDaniel Scheller { 1553c4e0415SDaniel Scheller return i2c_write(state->base->i2c, state->base->adr, data, len); 1563c4e0415SDaniel Scheller } 1573c4e0415SDaniel Scheller 1583c4e0415SDaniel Scheller static int read_register_unlocked(struct mxl *state, u32 reg, u32 *val) 1593c4e0415SDaniel Scheller { 1603c4e0415SDaniel Scheller int stat; 1613c4e0415SDaniel Scheller u8 data[MXL_HYDRA_REG_SIZE_IN_BYTES + MXL_HYDRA_I2C_HDR_SIZE] = { 1623c4e0415SDaniel Scheller MXL_HYDRA_PLID_REG_READ, 0x04, 1633c4e0415SDaniel Scheller GET_BYTE(reg, 0), GET_BYTE(reg, 1), 1643c4e0415SDaniel Scheller GET_BYTE(reg, 2), GET_BYTE(reg, 3), 1653c4e0415SDaniel Scheller }; 1663c4e0415SDaniel Scheller 1673c4e0415SDaniel Scheller stat = i2cwrite(state, data, 1683c4e0415SDaniel Scheller MXL_HYDRA_REG_SIZE_IN_BYTES + MXL_HYDRA_I2C_HDR_SIZE); 1693c4e0415SDaniel Scheller if (stat) 1703c4e0415SDaniel Scheller dev_err(state->i2cdev, "i2c read error 1\n"); 1713c4e0415SDaniel Scheller if (!stat) 1723c4e0415SDaniel Scheller stat = i2cread(state, (u8 *) val, 1733c4e0415SDaniel Scheller MXL_HYDRA_REG_SIZE_IN_BYTES); 1743c4e0415SDaniel Scheller le32_to_cpus(val); 1753c4e0415SDaniel Scheller if (stat) 1763c4e0415SDaniel Scheller dev_err(state->i2cdev, "i2c read error 2\n"); 1773c4e0415SDaniel Scheller return stat; 1783c4e0415SDaniel Scheller } 1793c4e0415SDaniel Scheller 1803c4e0415SDaniel Scheller #define DMA_I2C_INTERRUPT_ADDR 0x8000011C 1813c4e0415SDaniel Scheller #define DMA_INTR_PROT_WR_CMP 0x08 1823c4e0415SDaniel Scheller 1833c4e0415SDaniel Scheller static int send_command(struct mxl *state, u32 size, u8 *buf) 1843c4e0415SDaniel Scheller { 1853c4e0415SDaniel Scheller int stat; 1863c4e0415SDaniel Scheller u32 val, count = 10; 1873c4e0415SDaniel Scheller 1883c4e0415SDaniel Scheller mutex_lock(&state->base->i2c_lock); 1893c4e0415SDaniel Scheller if (state->base->fwversion > 0x02010109) { 1903c4e0415SDaniel Scheller read_register_unlocked(state, DMA_I2C_INTERRUPT_ADDR, &val); 1913c4e0415SDaniel Scheller if (DMA_INTR_PROT_WR_CMP & val) 1923c4e0415SDaniel Scheller dev_info(state->i2cdev, "%s busy\n", __func__); 1933c4e0415SDaniel Scheller while ((DMA_INTR_PROT_WR_CMP & val) && --count) { 1943c4e0415SDaniel Scheller mutex_unlock(&state->base->i2c_lock); 1953c4e0415SDaniel Scheller usleep_range(1000, 2000); 1963c4e0415SDaniel Scheller mutex_lock(&state->base->i2c_lock); 1973c4e0415SDaniel Scheller read_register_unlocked(state, DMA_I2C_INTERRUPT_ADDR, 1983c4e0415SDaniel Scheller &val); 1993c4e0415SDaniel Scheller } 2003c4e0415SDaniel Scheller if (!count) { 2013c4e0415SDaniel Scheller dev_info(state->i2cdev, "%s busy\n", __func__); 2023c4e0415SDaniel Scheller mutex_unlock(&state->base->i2c_lock); 2033c4e0415SDaniel Scheller return -EBUSY; 2043c4e0415SDaniel Scheller } 2053c4e0415SDaniel Scheller } 2063c4e0415SDaniel Scheller stat = i2cwrite(state, buf, size); 2073c4e0415SDaniel Scheller mutex_unlock(&state->base->i2c_lock); 2083c4e0415SDaniel Scheller return stat; 2093c4e0415SDaniel Scheller } 2103c4e0415SDaniel Scheller 2113c4e0415SDaniel Scheller static int write_register(struct mxl *state, u32 reg, u32 val) 2123c4e0415SDaniel Scheller { 2133c4e0415SDaniel Scheller int stat; 2143c4e0415SDaniel Scheller u8 data[MXL_HYDRA_REG_WRITE_LEN] = { 2153c4e0415SDaniel Scheller MXL_HYDRA_PLID_REG_WRITE, 0x08, 2163c4e0415SDaniel Scheller BYTE0(reg), BYTE1(reg), BYTE2(reg), BYTE3(reg), 2173c4e0415SDaniel Scheller BYTE0(val), BYTE1(val), BYTE2(val), BYTE3(val), 2183c4e0415SDaniel Scheller }; 2193c4e0415SDaniel Scheller mutex_lock(&state->base->i2c_lock); 2203c4e0415SDaniel Scheller stat = i2cwrite(state, data, sizeof(data)); 2213c4e0415SDaniel Scheller mutex_unlock(&state->base->i2c_lock); 2223c4e0415SDaniel Scheller if (stat) 2233c4e0415SDaniel Scheller dev_err(state->i2cdev, "i2c write error\n"); 2243c4e0415SDaniel Scheller return stat; 2253c4e0415SDaniel Scheller } 2263c4e0415SDaniel Scheller 2273c4e0415SDaniel Scheller static int write_firmware_block(struct mxl *state, 2283c4e0415SDaniel Scheller u32 reg, u32 size, u8 *reg_data_ptr) 2293c4e0415SDaniel Scheller { 2303c4e0415SDaniel Scheller int stat; 2313c4e0415SDaniel Scheller u8 *buf = state->base->buf; 2323c4e0415SDaniel Scheller 2333c4e0415SDaniel Scheller mutex_lock(&state->base->i2c_lock); 2343c4e0415SDaniel Scheller buf[0] = MXL_HYDRA_PLID_REG_WRITE; 2353c4e0415SDaniel Scheller buf[1] = size + 4; 2363c4e0415SDaniel Scheller buf[2] = GET_BYTE(reg, 0); 2373c4e0415SDaniel Scheller buf[3] = GET_BYTE(reg, 1); 2383c4e0415SDaniel Scheller buf[4] = GET_BYTE(reg, 2); 2393c4e0415SDaniel Scheller buf[5] = GET_BYTE(reg, 3); 2403c4e0415SDaniel Scheller memcpy(&buf[6], reg_data_ptr, size); 2413c4e0415SDaniel Scheller stat = i2cwrite(state, buf, 2423c4e0415SDaniel Scheller MXL_HYDRA_I2C_HDR_SIZE + 2433c4e0415SDaniel Scheller MXL_HYDRA_REG_SIZE_IN_BYTES + size); 2443c4e0415SDaniel Scheller mutex_unlock(&state->base->i2c_lock); 2453c4e0415SDaniel Scheller if (stat) 2463c4e0415SDaniel Scheller dev_err(state->i2cdev, "fw block write failed\n"); 2473c4e0415SDaniel Scheller return stat; 2483c4e0415SDaniel Scheller } 2493c4e0415SDaniel Scheller 2503c4e0415SDaniel Scheller static int read_register(struct mxl *state, u32 reg, u32 *val) 2513c4e0415SDaniel Scheller { 2523c4e0415SDaniel Scheller int stat; 2533c4e0415SDaniel Scheller u8 data[MXL_HYDRA_REG_SIZE_IN_BYTES + MXL_HYDRA_I2C_HDR_SIZE] = { 2543c4e0415SDaniel Scheller MXL_HYDRA_PLID_REG_READ, 0x04, 2553c4e0415SDaniel Scheller GET_BYTE(reg, 0), GET_BYTE(reg, 1), 2563c4e0415SDaniel Scheller GET_BYTE(reg, 2), GET_BYTE(reg, 3), 2573c4e0415SDaniel Scheller }; 2583c4e0415SDaniel Scheller 2593c4e0415SDaniel Scheller mutex_lock(&state->base->i2c_lock); 2603c4e0415SDaniel Scheller stat = i2cwrite(state, data, 2613c4e0415SDaniel Scheller MXL_HYDRA_REG_SIZE_IN_BYTES + MXL_HYDRA_I2C_HDR_SIZE); 2623c4e0415SDaniel Scheller if (stat) 2633c4e0415SDaniel Scheller dev_err(state->i2cdev, "i2c read error 1\n"); 2643c4e0415SDaniel Scheller if (!stat) 2653c4e0415SDaniel Scheller stat = i2cread(state, (u8 *) val, 2663c4e0415SDaniel Scheller MXL_HYDRA_REG_SIZE_IN_BYTES); 2673c4e0415SDaniel Scheller mutex_unlock(&state->base->i2c_lock); 2683c4e0415SDaniel Scheller le32_to_cpus(val); 2693c4e0415SDaniel Scheller if (stat) 2703c4e0415SDaniel Scheller dev_err(state->i2cdev, "i2c read error 2\n"); 2713c4e0415SDaniel Scheller return stat; 2723c4e0415SDaniel Scheller } 2733c4e0415SDaniel Scheller 2743c4e0415SDaniel Scheller static int read_register_block(struct mxl *state, u32 reg, u32 size, u8 *data) 2753c4e0415SDaniel Scheller { 2763c4e0415SDaniel Scheller int stat; 2773c4e0415SDaniel Scheller u8 *buf = state->base->buf; 2783c4e0415SDaniel Scheller 2793c4e0415SDaniel Scheller mutex_lock(&state->base->i2c_lock); 2803c4e0415SDaniel Scheller 2813c4e0415SDaniel Scheller buf[0] = MXL_HYDRA_PLID_REG_READ; 2823c4e0415SDaniel Scheller buf[1] = size + 4; 2833c4e0415SDaniel Scheller buf[2] = GET_BYTE(reg, 0); 2843c4e0415SDaniel Scheller buf[3] = GET_BYTE(reg, 1); 2853c4e0415SDaniel Scheller buf[4] = GET_BYTE(reg, 2); 2863c4e0415SDaniel Scheller buf[5] = GET_BYTE(reg, 3); 2873c4e0415SDaniel Scheller stat = i2cwrite(state, buf, 2883c4e0415SDaniel Scheller MXL_HYDRA_I2C_HDR_SIZE + MXL_HYDRA_REG_SIZE_IN_BYTES); 2893c4e0415SDaniel Scheller if (!stat) { 2903c4e0415SDaniel Scheller stat = i2cread(state, data, size); 2913c4e0415SDaniel Scheller convert_endian(MXL_ENABLE_BIG_ENDIAN, size, data); 2923c4e0415SDaniel Scheller } 2933c4e0415SDaniel Scheller mutex_unlock(&state->base->i2c_lock); 2943c4e0415SDaniel Scheller return stat; 2953c4e0415SDaniel Scheller } 2963c4e0415SDaniel Scheller 2973c4e0415SDaniel Scheller static int read_by_mnemonic(struct mxl *state, 2983c4e0415SDaniel Scheller u32 reg, u8 lsbloc, u8 numofbits, u32 *val) 2993c4e0415SDaniel Scheller { 3003c4e0415SDaniel Scheller u32 data = 0, mask = 0; 3013c4e0415SDaniel Scheller int stat; 3023c4e0415SDaniel Scheller 3033c4e0415SDaniel Scheller stat = read_register(state, reg, &data); 3043c4e0415SDaniel Scheller if (stat) 3053c4e0415SDaniel Scheller return stat; 3063c4e0415SDaniel Scheller mask = MXL_GET_REG_MASK_32(lsbloc, numofbits); 3073c4e0415SDaniel Scheller data &= mask; 3083c4e0415SDaniel Scheller data >>= lsbloc; 3093c4e0415SDaniel Scheller *val = data; 3103c4e0415SDaniel Scheller return 0; 3113c4e0415SDaniel Scheller } 3123c4e0415SDaniel Scheller 3133c4e0415SDaniel Scheller 3143c4e0415SDaniel Scheller static int update_by_mnemonic(struct mxl *state, 3153c4e0415SDaniel Scheller u32 reg, u8 lsbloc, u8 numofbits, u32 val) 3163c4e0415SDaniel Scheller { 3173c4e0415SDaniel Scheller u32 data, mask; 3183c4e0415SDaniel Scheller int stat; 3193c4e0415SDaniel Scheller 3203c4e0415SDaniel Scheller stat = read_register(state, reg, &data); 3213c4e0415SDaniel Scheller if (stat) 3223c4e0415SDaniel Scheller return stat; 3233c4e0415SDaniel Scheller mask = MXL_GET_REG_MASK_32(lsbloc, numofbits); 3243c4e0415SDaniel Scheller data = (data & ~mask) | ((val << lsbloc) & mask); 3253c4e0415SDaniel Scheller stat = write_register(state, reg, data); 3263c4e0415SDaniel Scheller return stat; 3273c4e0415SDaniel Scheller } 3283c4e0415SDaniel Scheller 3293c4e0415SDaniel Scheller static int firmware_is_alive(struct mxl *state) 3303c4e0415SDaniel Scheller { 3313c4e0415SDaniel Scheller u32 hb0, hb1; 3323c4e0415SDaniel Scheller 3333c4e0415SDaniel Scheller if (read_register(state, HYDRA_HEAR_BEAT, &hb0)) 3343c4e0415SDaniel Scheller return 0; 3353c4e0415SDaniel Scheller msleep(20); 3363c4e0415SDaniel Scheller if (read_register(state, HYDRA_HEAR_BEAT, &hb1)) 3373c4e0415SDaniel Scheller return 0; 3383c4e0415SDaniel Scheller if (hb1 == hb0) 3393c4e0415SDaniel Scheller return 0; 3403c4e0415SDaniel Scheller return 1; 3413c4e0415SDaniel Scheller } 3423c4e0415SDaniel Scheller 3433c4e0415SDaniel Scheller static int init(struct dvb_frontend *fe) 3443c4e0415SDaniel Scheller { 3453c4e0415SDaniel Scheller struct dtv_frontend_properties *p = &fe->dtv_property_cache; 3463c4e0415SDaniel Scheller 3473c4e0415SDaniel Scheller /* init fe stats */ 3483c4e0415SDaniel Scheller p->strength.len = 1; 3493c4e0415SDaniel Scheller p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 3503c4e0415SDaniel Scheller p->cnr.len = 1; 3513c4e0415SDaniel Scheller p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 3523c4e0415SDaniel Scheller p->pre_bit_error.len = 1; 3533c4e0415SDaniel Scheller p->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 3543c4e0415SDaniel Scheller p->pre_bit_count.len = 1; 3553c4e0415SDaniel Scheller p->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 3563c4e0415SDaniel Scheller p->post_bit_error.len = 1; 3573c4e0415SDaniel Scheller p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 3583c4e0415SDaniel Scheller p->post_bit_count.len = 1; 3593c4e0415SDaniel Scheller p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 3603c4e0415SDaniel Scheller 3613c4e0415SDaniel Scheller return 0; 3623c4e0415SDaniel Scheller } 3633c4e0415SDaniel Scheller 3643c4e0415SDaniel Scheller static void release(struct dvb_frontend *fe) 3653c4e0415SDaniel Scheller { 3663c4e0415SDaniel Scheller struct mxl *state = fe->demodulator_priv; 3673c4e0415SDaniel Scheller 3683c4e0415SDaniel Scheller list_del(&state->mxl); 3693c4e0415SDaniel Scheller /* Release one frontend, two more shall take its place! */ 3703c4e0415SDaniel Scheller state->base->count--; 3713c4e0415SDaniel Scheller if (state->base->count == 0) { 3723c4e0415SDaniel Scheller list_del(&state->base->mxllist); 3733c4e0415SDaniel Scheller kfree(state->base); 3743c4e0415SDaniel Scheller } 3753c4e0415SDaniel Scheller kfree(state); 3763c4e0415SDaniel Scheller } 3773c4e0415SDaniel Scheller 3788d718e53SLuc Van Oostenryck static enum dvbfe_algo get_algo(struct dvb_frontend *fe) 3793c4e0415SDaniel Scheller { 3803c4e0415SDaniel Scheller return DVBFE_ALGO_HW; 3813c4e0415SDaniel Scheller } 3823c4e0415SDaniel Scheller 38362474660SDaniel Scheller static u32 gold2root(u32 gold) 38462474660SDaniel Scheller { 38562474660SDaniel Scheller u32 x, g, tmp = gold; 38662474660SDaniel Scheller 38762474660SDaniel Scheller if (tmp >= 0x3ffff) 38862474660SDaniel Scheller tmp = 0; 38962474660SDaniel Scheller for (g = 0, x = 1; g < tmp; g++) 39062474660SDaniel Scheller x = (((x ^ (x >> 7)) & 1) << 17) | (x >> 1); 39162474660SDaniel Scheller return x; 39262474660SDaniel Scheller } 39362474660SDaniel Scheller 39462474660SDaniel Scheller static int cfg_scrambler(struct mxl *state, u32 gold) 39562474660SDaniel Scheller { 39662474660SDaniel Scheller u32 root; 39762474660SDaniel Scheller u8 buf[26] = { 39862474660SDaniel Scheller MXL_HYDRA_PLID_CMD_WRITE, 24, 39962474660SDaniel Scheller 0, MXL_HYDRA_DEMOD_SCRAMBLE_CODE_CMD, 0, 0, 40062474660SDaniel Scheller state->demod, 0, 0, 0, 40162474660SDaniel Scheller 0, 0, 0, 0, 0, 0, 0, 0, 40262474660SDaniel Scheller 0, 0, 0, 0, 1, 0, 0, 0, 40362474660SDaniel Scheller }; 40462474660SDaniel Scheller 40562474660SDaniel Scheller root = gold2root(gold); 40662474660SDaniel Scheller 40762474660SDaniel Scheller buf[25] = (root >> 24) & 0xff; 40862474660SDaniel Scheller buf[24] = (root >> 16) & 0xff; 40962474660SDaniel Scheller buf[23] = (root >> 8) & 0xff; 41062474660SDaniel Scheller buf[22] = root & 0xff; 41162474660SDaniel Scheller 41262474660SDaniel Scheller return send_command(state, sizeof(buf), buf); 41362474660SDaniel Scheller } 41462474660SDaniel Scheller 4153c4e0415SDaniel Scheller static int cfg_demod_abort_tune(struct mxl *state) 4163c4e0415SDaniel Scheller { 4173c4e0415SDaniel Scheller struct MXL_HYDRA_DEMOD_ABORT_TUNE_T abort_tune_cmd; 4183c4e0415SDaniel Scheller u8 cmd_size = sizeof(abort_tune_cmd); 4193c4e0415SDaniel Scheller u8 cmd_buff[MXL_HYDRA_OEM_MAX_CMD_BUFF_LEN]; 4203c4e0415SDaniel Scheller 4213c4e0415SDaniel Scheller abort_tune_cmd.demod_id = state->demod; 4223c4e0415SDaniel Scheller BUILD_HYDRA_CMD(MXL_HYDRA_ABORT_TUNE_CMD, MXL_CMD_WRITE, 4233c4e0415SDaniel Scheller cmd_size, &abort_tune_cmd, cmd_buff); 4243c4e0415SDaniel Scheller return send_command(state, cmd_size + MXL_HYDRA_CMD_HEADER_SIZE, 4253c4e0415SDaniel Scheller &cmd_buff[0]); 4263c4e0415SDaniel Scheller } 4273c4e0415SDaniel Scheller 4283c4e0415SDaniel Scheller static int send_master_cmd(struct dvb_frontend *fe, 4293c4e0415SDaniel Scheller struct dvb_diseqc_master_cmd *cmd) 4303c4e0415SDaniel Scheller { 4313c4e0415SDaniel Scheller /*struct mxl *state = fe->demodulator_priv;*/ 4323c4e0415SDaniel Scheller 4333c4e0415SDaniel Scheller return 0; /*CfgDemodAbortTune(state);*/ 4343c4e0415SDaniel Scheller } 4353c4e0415SDaniel Scheller 4363c4e0415SDaniel Scheller static int set_parameters(struct dvb_frontend *fe) 4373c4e0415SDaniel Scheller { 4383c4e0415SDaniel Scheller struct mxl *state = fe->demodulator_priv; 4393c4e0415SDaniel Scheller struct dtv_frontend_properties *p = &fe->dtv_property_cache; 4403c4e0415SDaniel Scheller struct MXL_HYDRA_DEMOD_PARAM_T demod_chan_cfg; 4413c4e0415SDaniel Scheller u8 cmd_size = sizeof(demod_chan_cfg); 4423c4e0415SDaniel Scheller u8 cmd_buff[MXL_HYDRA_OEM_MAX_CMD_BUFF_LEN]; 4433c4e0415SDaniel Scheller u32 srange = 10; 4443c4e0415SDaniel Scheller int stat; 4453c4e0415SDaniel Scheller 4463c4e0415SDaniel Scheller if (p->frequency < 950000 || p->frequency > 2150000) 4473c4e0415SDaniel Scheller return -EINVAL; 4483c4e0415SDaniel Scheller if (p->symbol_rate < 1000000 || p->symbol_rate > 45000000) 4493c4e0415SDaniel Scheller return -EINVAL; 4503c4e0415SDaniel Scheller 4513c4e0415SDaniel Scheller /* CfgDemodAbortTune(state); */ 4523c4e0415SDaniel Scheller 4533c4e0415SDaniel Scheller switch (p->delivery_system) { 4543c4e0415SDaniel Scheller case SYS_DSS: 4553c4e0415SDaniel Scheller demod_chan_cfg.standard = MXL_HYDRA_DSS; 4563c4e0415SDaniel Scheller demod_chan_cfg.roll_off = MXL_HYDRA_ROLLOFF_AUTO; 4573c4e0415SDaniel Scheller break; 4583c4e0415SDaniel Scheller case SYS_DVBS: 4593c4e0415SDaniel Scheller srange = p->symbol_rate / 1000000; 4603c4e0415SDaniel Scheller if (srange > 10) 4613c4e0415SDaniel Scheller srange = 10; 4623c4e0415SDaniel Scheller demod_chan_cfg.standard = MXL_HYDRA_DVBS; 4633c4e0415SDaniel Scheller demod_chan_cfg.roll_off = MXL_HYDRA_ROLLOFF_0_35; 4643c4e0415SDaniel Scheller demod_chan_cfg.modulation_scheme = MXL_HYDRA_MOD_QPSK; 4653c4e0415SDaniel Scheller demod_chan_cfg.pilots = MXL_HYDRA_PILOTS_OFF; 4663c4e0415SDaniel Scheller break; 4673c4e0415SDaniel Scheller case SYS_DVBS2: 4683c4e0415SDaniel Scheller demod_chan_cfg.standard = MXL_HYDRA_DVBS2; 4693c4e0415SDaniel Scheller demod_chan_cfg.roll_off = MXL_HYDRA_ROLLOFF_AUTO; 4703c4e0415SDaniel Scheller demod_chan_cfg.modulation_scheme = MXL_HYDRA_MOD_AUTO; 4713c4e0415SDaniel Scheller demod_chan_cfg.pilots = MXL_HYDRA_PILOTS_AUTO; 47262474660SDaniel Scheller cfg_scrambler(state, p->scrambling_sequence_index); 4733c4e0415SDaniel Scheller break; 4743c4e0415SDaniel Scheller default: 4753c4e0415SDaniel Scheller return -EINVAL; 4763c4e0415SDaniel Scheller } 4773c4e0415SDaniel Scheller demod_chan_cfg.tuner_index = state->tuner; 4783c4e0415SDaniel Scheller demod_chan_cfg.demod_index = state->demod; 4793c4e0415SDaniel Scheller demod_chan_cfg.frequency_in_hz = p->frequency * 1000; 4803c4e0415SDaniel Scheller demod_chan_cfg.symbol_rate_in_hz = p->symbol_rate; 4813c4e0415SDaniel Scheller demod_chan_cfg.max_carrier_offset_in_mhz = srange; 4823c4e0415SDaniel Scheller demod_chan_cfg.spectrum_inversion = MXL_HYDRA_SPECTRUM_AUTO; 4833c4e0415SDaniel Scheller demod_chan_cfg.fec_code_rate = MXL_HYDRA_FEC_AUTO; 4843c4e0415SDaniel Scheller 4853c4e0415SDaniel Scheller mutex_lock(&state->base->tune_lock); 4863c4e0415SDaniel Scheller if (time_after(jiffies + msecs_to_jiffies(200), 4873c4e0415SDaniel Scheller state->base->next_tune)) 4883c4e0415SDaniel Scheller while (time_before(jiffies, state->base->next_tune)) 4893c4e0415SDaniel Scheller usleep_range(10000, 11000); 4903c4e0415SDaniel Scheller state->base->next_tune = jiffies + msecs_to_jiffies(100); 4913c4e0415SDaniel Scheller state->tuner_in_use = state->tuner; 4923c4e0415SDaniel Scheller BUILD_HYDRA_CMD(MXL_HYDRA_DEMOD_SET_PARAM_CMD, MXL_CMD_WRITE, 4933c4e0415SDaniel Scheller cmd_size, &demod_chan_cfg, cmd_buff); 4943c4e0415SDaniel Scheller stat = send_command(state, cmd_size + MXL_HYDRA_CMD_HEADER_SIZE, 4953c4e0415SDaniel Scheller &cmd_buff[0]); 4963c4e0415SDaniel Scheller mutex_unlock(&state->base->tune_lock); 4973c4e0415SDaniel Scheller return stat; 4983c4e0415SDaniel Scheller } 4993c4e0415SDaniel Scheller 5003c4e0415SDaniel Scheller static int enable_tuner(struct mxl *state, u32 tuner, u32 enable); 5013c4e0415SDaniel Scheller 5023c4e0415SDaniel Scheller static int sleep(struct dvb_frontend *fe) 5033c4e0415SDaniel Scheller { 5043c4e0415SDaniel Scheller struct mxl *state = fe->demodulator_priv; 5053c4e0415SDaniel Scheller struct mxl *p; 5063c4e0415SDaniel Scheller 5073c4e0415SDaniel Scheller cfg_demod_abort_tune(state); 5083c4e0415SDaniel Scheller if (state->tuner_in_use != 0xffffffff) { 5093c4e0415SDaniel Scheller mutex_lock(&state->base->tune_lock); 5103c4e0415SDaniel Scheller state->tuner_in_use = 0xffffffff; 5113c4e0415SDaniel Scheller list_for_each_entry(p, &state->base->mxls, mxl) { 5123c4e0415SDaniel Scheller if (p->tuner_in_use == state->tuner) 5133c4e0415SDaniel Scheller break; 5143c4e0415SDaniel Scheller } 5153c4e0415SDaniel Scheller if (&p->mxl == &state->base->mxls) 5163c4e0415SDaniel Scheller enable_tuner(state, state->tuner, 0); 5173c4e0415SDaniel Scheller mutex_unlock(&state->base->tune_lock); 5183c4e0415SDaniel Scheller } 5193c4e0415SDaniel Scheller return 0; 5203c4e0415SDaniel Scheller } 5213c4e0415SDaniel Scheller 5223c4e0415SDaniel Scheller static int read_snr(struct dvb_frontend *fe) 5233c4e0415SDaniel Scheller { 5243c4e0415SDaniel Scheller struct mxl *state = fe->demodulator_priv; 5253c4e0415SDaniel Scheller int stat; 5263c4e0415SDaniel Scheller u32 reg_data = 0; 5273c4e0415SDaniel Scheller struct dtv_frontend_properties *p = &fe->dtv_property_cache; 5283c4e0415SDaniel Scheller 5293c4e0415SDaniel Scheller mutex_lock(&state->base->status_lock); 5303c4e0415SDaniel Scheller HYDRA_DEMOD_STATUS_LOCK(state, state->demod); 5313c4e0415SDaniel Scheller stat = read_register(state, (HYDRA_DMD_SNR_ADDR_OFFSET + 5323c4e0415SDaniel Scheller HYDRA_DMD_STATUS_OFFSET(state->demod)), 5333c4e0415SDaniel Scheller ®_data); 5343c4e0415SDaniel Scheller HYDRA_DEMOD_STATUS_UNLOCK(state, state->demod); 5353c4e0415SDaniel Scheller mutex_unlock(&state->base->status_lock); 5363c4e0415SDaniel Scheller 5373c4e0415SDaniel Scheller p->cnr.stat[0].scale = FE_SCALE_DECIBEL; 5383c4e0415SDaniel Scheller p->cnr.stat[0].svalue = (s16)reg_data * 10; 5393c4e0415SDaniel Scheller 5403c4e0415SDaniel Scheller return stat; 5413c4e0415SDaniel Scheller } 5423c4e0415SDaniel Scheller 5433c4e0415SDaniel Scheller static int read_ber(struct dvb_frontend *fe) 5443c4e0415SDaniel Scheller { 5453c4e0415SDaniel Scheller struct mxl *state = fe->demodulator_priv; 5463c4e0415SDaniel Scheller struct dtv_frontend_properties *p = &fe->dtv_property_cache; 5473c4e0415SDaniel Scheller u32 reg[8]; 5483c4e0415SDaniel Scheller 5493c4e0415SDaniel Scheller mutex_lock(&state->base->status_lock); 5503c4e0415SDaniel Scheller HYDRA_DEMOD_STATUS_LOCK(state, state->demod); 5513c4e0415SDaniel Scheller read_register_block(state, 5523c4e0415SDaniel Scheller (HYDRA_DMD_DVBS_1ST_CORR_RS_ERRORS_ADDR_OFFSET + 5533c4e0415SDaniel Scheller HYDRA_DMD_STATUS_OFFSET(state->demod)), 5543c4e0415SDaniel Scheller (4 * sizeof(u32)), 5553c4e0415SDaniel Scheller (u8 *) ®[0]); 5563c4e0415SDaniel Scheller HYDRA_DEMOD_STATUS_UNLOCK(state, state->demod); 5573c4e0415SDaniel Scheller 5583c4e0415SDaniel Scheller switch (p->delivery_system) { 5593c4e0415SDaniel Scheller case SYS_DSS: 5603c4e0415SDaniel Scheller case SYS_DVBS: 5613c4e0415SDaniel Scheller p->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER; 5623c4e0415SDaniel Scheller p->pre_bit_error.stat[0].uvalue = reg[2]; 5633c4e0415SDaniel Scheller p->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER; 5643c4e0415SDaniel Scheller p->pre_bit_count.stat[0].uvalue = reg[3]; 5653c4e0415SDaniel Scheller break; 5663c4e0415SDaniel Scheller default: 5673c4e0415SDaniel Scheller break; 5683c4e0415SDaniel Scheller } 5693c4e0415SDaniel Scheller 5703c4e0415SDaniel Scheller read_register_block(state, 5713c4e0415SDaniel Scheller (HYDRA_DMD_DVBS2_CRC_ERRORS_ADDR_OFFSET + 5723c4e0415SDaniel Scheller HYDRA_DMD_STATUS_OFFSET(state->demod)), 5733c4e0415SDaniel Scheller (7 * sizeof(u32)), 5743c4e0415SDaniel Scheller (u8 *) ®[0]); 5753c4e0415SDaniel Scheller 5763c4e0415SDaniel Scheller switch (p->delivery_system) { 5773c4e0415SDaniel Scheller case SYS_DSS: 5783c4e0415SDaniel Scheller case SYS_DVBS: 5793c4e0415SDaniel Scheller p->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; 5803c4e0415SDaniel Scheller p->post_bit_error.stat[0].uvalue = reg[5]; 5813c4e0415SDaniel Scheller p->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; 5823c4e0415SDaniel Scheller p->post_bit_count.stat[0].uvalue = reg[6]; 5833c4e0415SDaniel Scheller break; 5843c4e0415SDaniel Scheller case SYS_DVBS2: 5853c4e0415SDaniel Scheller p->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; 5863c4e0415SDaniel Scheller p->post_bit_error.stat[0].uvalue = reg[1]; 5873c4e0415SDaniel Scheller p->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; 5883c4e0415SDaniel Scheller p->post_bit_count.stat[0].uvalue = reg[2]; 5893c4e0415SDaniel Scheller break; 5903c4e0415SDaniel Scheller default: 5913c4e0415SDaniel Scheller break; 5923c4e0415SDaniel Scheller } 5933c4e0415SDaniel Scheller 5943c4e0415SDaniel Scheller mutex_unlock(&state->base->status_lock); 5953c4e0415SDaniel Scheller 5963c4e0415SDaniel Scheller return 0; 5973c4e0415SDaniel Scheller } 5983c4e0415SDaniel Scheller 5993c4e0415SDaniel Scheller static int read_signal_strength(struct dvb_frontend *fe) 6003c4e0415SDaniel Scheller { 6013c4e0415SDaniel Scheller struct mxl *state = fe->demodulator_priv; 6023c4e0415SDaniel Scheller struct dtv_frontend_properties *p = &fe->dtv_property_cache; 6033c4e0415SDaniel Scheller int stat; 6043c4e0415SDaniel Scheller u32 reg_data = 0; 6053c4e0415SDaniel Scheller 6063c4e0415SDaniel Scheller mutex_lock(&state->base->status_lock); 6073c4e0415SDaniel Scheller HYDRA_DEMOD_STATUS_LOCK(state, state->demod); 6083c4e0415SDaniel Scheller stat = read_register(state, (HYDRA_DMD_STATUS_INPUT_POWER_ADDR + 6093c4e0415SDaniel Scheller HYDRA_DMD_STATUS_OFFSET(state->demod)), 6103c4e0415SDaniel Scheller ®_data); 6113c4e0415SDaniel Scheller HYDRA_DEMOD_STATUS_UNLOCK(state, state->demod); 6123c4e0415SDaniel Scheller mutex_unlock(&state->base->status_lock); 6133c4e0415SDaniel Scheller 6143c4e0415SDaniel Scheller p->strength.stat[0].scale = FE_SCALE_DECIBEL; 6153c4e0415SDaniel Scheller p->strength.stat[0].svalue = (s16) reg_data * 10; /* fix scale */ 6163c4e0415SDaniel Scheller 6173c4e0415SDaniel Scheller return stat; 6183c4e0415SDaniel Scheller } 6193c4e0415SDaniel Scheller 6203c4e0415SDaniel Scheller static int read_status(struct dvb_frontend *fe, enum fe_status *status) 6213c4e0415SDaniel Scheller { 6223c4e0415SDaniel Scheller struct mxl *state = fe->demodulator_priv; 6233c4e0415SDaniel Scheller struct dtv_frontend_properties *p = &fe->dtv_property_cache; 6243c4e0415SDaniel Scheller u32 reg_data = 0; 6253c4e0415SDaniel Scheller 6263c4e0415SDaniel Scheller mutex_lock(&state->base->status_lock); 6273c4e0415SDaniel Scheller HYDRA_DEMOD_STATUS_LOCK(state, state->demod); 6283c4e0415SDaniel Scheller read_register(state, (HYDRA_DMD_LOCK_STATUS_ADDR_OFFSET + 6293c4e0415SDaniel Scheller HYDRA_DMD_STATUS_OFFSET(state->demod)), 6303c4e0415SDaniel Scheller ®_data); 6313c4e0415SDaniel Scheller HYDRA_DEMOD_STATUS_UNLOCK(state, state->demod); 6323c4e0415SDaniel Scheller mutex_unlock(&state->base->status_lock); 6333c4e0415SDaniel Scheller 6343c4e0415SDaniel Scheller *status = (reg_data == 1) ? 0x1f : 0; 6353c4e0415SDaniel Scheller 6363c4e0415SDaniel Scheller /* signal statistics */ 6373c4e0415SDaniel Scheller 6383c4e0415SDaniel Scheller /* signal strength is always available */ 6393c4e0415SDaniel Scheller read_signal_strength(fe); 6403c4e0415SDaniel Scheller 6413c4e0415SDaniel Scheller if (*status & FE_HAS_CARRIER) 6423c4e0415SDaniel Scheller read_snr(fe); 6433c4e0415SDaniel Scheller else 6443c4e0415SDaniel Scheller p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 6453c4e0415SDaniel Scheller 6463c4e0415SDaniel Scheller if (*status & FE_HAS_SYNC) 6473c4e0415SDaniel Scheller read_ber(fe); 6483c4e0415SDaniel Scheller else { 6493c4e0415SDaniel Scheller p->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 6503c4e0415SDaniel Scheller p->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 6513c4e0415SDaniel Scheller p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 6523c4e0415SDaniel Scheller p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; 6533c4e0415SDaniel Scheller } 6543c4e0415SDaniel Scheller 6553c4e0415SDaniel Scheller return 0; 6563c4e0415SDaniel Scheller } 6573c4e0415SDaniel Scheller 6583c4e0415SDaniel Scheller static int tune(struct dvb_frontend *fe, bool re_tune, 6593c4e0415SDaniel Scheller unsigned int mode_flags, 6603c4e0415SDaniel Scheller unsigned int *delay, enum fe_status *status) 6613c4e0415SDaniel Scheller { 6623c4e0415SDaniel Scheller struct mxl *state = fe->demodulator_priv; 6633c4e0415SDaniel Scheller int r = 0; 6643c4e0415SDaniel Scheller 6653c4e0415SDaniel Scheller *delay = HZ / 2; 6663c4e0415SDaniel Scheller if (re_tune) { 6673c4e0415SDaniel Scheller r = set_parameters(fe); 6683c4e0415SDaniel Scheller if (r) 6693c4e0415SDaniel Scheller return r; 6703c4e0415SDaniel Scheller state->tune_time = jiffies; 6713c4e0415SDaniel Scheller } 6723c4e0415SDaniel Scheller 6732919d12dSMauro Carvalho Chehab return read_status(fe, status); 6743c4e0415SDaniel Scheller } 6753c4e0415SDaniel Scheller 6763c4e0415SDaniel Scheller static enum fe_code_rate conv_fec(enum MXL_HYDRA_FEC_E fec) 6773c4e0415SDaniel Scheller { 6783c4e0415SDaniel Scheller enum fe_code_rate fec2fec[11] = { 6793c4e0415SDaniel Scheller FEC_NONE, FEC_1_2, FEC_3_5, FEC_2_3, 6803c4e0415SDaniel Scheller FEC_3_4, FEC_4_5, FEC_5_6, FEC_6_7, 6813c4e0415SDaniel Scheller FEC_7_8, FEC_8_9, FEC_9_10 6823c4e0415SDaniel Scheller }; 6833c4e0415SDaniel Scheller 6843c4e0415SDaniel Scheller if (fec > MXL_HYDRA_FEC_9_10) 6853c4e0415SDaniel Scheller return FEC_NONE; 6863c4e0415SDaniel Scheller return fec2fec[fec]; 6873c4e0415SDaniel Scheller } 6883c4e0415SDaniel Scheller 6893c4e0415SDaniel Scheller static int get_frontend(struct dvb_frontend *fe, 6903c4e0415SDaniel Scheller struct dtv_frontend_properties *p) 6913c4e0415SDaniel Scheller { 6923c4e0415SDaniel Scheller struct mxl *state = fe->demodulator_priv; 6933c4e0415SDaniel Scheller u32 reg_data[MXL_DEMOD_CHAN_PARAMS_BUFF_SIZE]; 6943c4e0415SDaniel Scheller u32 freq; 6953c4e0415SDaniel Scheller 6963c4e0415SDaniel Scheller mutex_lock(&state->base->status_lock); 6973c4e0415SDaniel Scheller HYDRA_DEMOD_STATUS_LOCK(state, state->demod); 6983c4e0415SDaniel Scheller read_register_block(state, 6993c4e0415SDaniel Scheller (HYDRA_DMD_STANDARD_ADDR_OFFSET + 7003c4e0415SDaniel Scheller HYDRA_DMD_STATUS_OFFSET(state->demod)), 7013c4e0415SDaniel Scheller (MXL_DEMOD_CHAN_PARAMS_BUFF_SIZE * 4), /* 25 * 4 bytes */ 7023c4e0415SDaniel Scheller (u8 *) ®_data[0]); 7033c4e0415SDaniel Scheller /* read demod channel parameters */ 7043c4e0415SDaniel Scheller read_register_block(state, 7053c4e0415SDaniel Scheller (HYDRA_DMD_STATUS_CENTER_FREQ_IN_KHZ_ADDR + 7063c4e0415SDaniel Scheller HYDRA_DMD_STATUS_OFFSET(state->demod)), 7073c4e0415SDaniel Scheller (4), /* 4 bytes */ 7083c4e0415SDaniel Scheller (u8 *) &freq); 7093c4e0415SDaniel Scheller HYDRA_DEMOD_STATUS_UNLOCK(state, state->demod); 7103c4e0415SDaniel Scheller mutex_unlock(&state->base->status_lock); 7113c4e0415SDaniel Scheller 7123c4e0415SDaniel Scheller dev_dbg(state->i2cdev, "freq=%u delsys=%u srate=%u\n", 7133c4e0415SDaniel Scheller freq * 1000, reg_data[DMD_STANDARD_ADDR], 7143c4e0415SDaniel Scheller reg_data[DMD_SYMBOL_RATE_ADDR]); 7153c4e0415SDaniel Scheller p->symbol_rate = reg_data[DMD_SYMBOL_RATE_ADDR]; 7163c4e0415SDaniel Scheller p->frequency = freq; 7173c4e0415SDaniel Scheller /* 7183c4e0415SDaniel Scheller * p->delivery_system = 7193c4e0415SDaniel Scheller * (MXL_HYDRA_BCAST_STD_E) regData[DMD_STANDARD_ADDR]; 7203c4e0415SDaniel Scheller * p->inversion = 7213c4e0415SDaniel Scheller * (MXL_HYDRA_SPECTRUM_E) regData[DMD_SPECTRUM_INVERSION_ADDR]; 7223c4e0415SDaniel Scheller * freqSearchRangeKHz = 7233c4e0415SDaniel Scheller * (regData[DMD_FREQ_SEARCH_RANGE_IN_KHZ_ADDR]); 7243c4e0415SDaniel Scheller */ 7253c4e0415SDaniel Scheller 7263c4e0415SDaniel Scheller p->fec_inner = conv_fec(reg_data[DMD_FEC_CODE_RATE_ADDR]); 7273c4e0415SDaniel Scheller switch (p->delivery_system) { 7283c4e0415SDaniel Scheller case SYS_DSS: 7293c4e0415SDaniel Scheller break; 7303c4e0415SDaniel Scheller case SYS_DVBS2: 7313c4e0415SDaniel Scheller switch ((enum MXL_HYDRA_PILOTS_E) 7323c4e0415SDaniel Scheller reg_data[DMD_DVBS2_PILOT_ON_OFF_ADDR]) { 7333c4e0415SDaniel Scheller case MXL_HYDRA_PILOTS_OFF: 7343c4e0415SDaniel Scheller p->pilot = PILOT_OFF; 7353c4e0415SDaniel Scheller break; 7363c4e0415SDaniel Scheller case MXL_HYDRA_PILOTS_ON: 7373c4e0415SDaniel Scheller p->pilot = PILOT_ON; 7383c4e0415SDaniel Scheller break; 7393c4e0415SDaniel Scheller default: 7403c4e0415SDaniel Scheller break; 7413c4e0415SDaniel Scheller } 742dfb7bcf0SMauro Carvalho Chehab /* Fall through */ 7433c4e0415SDaniel Scheller case SYS_DVBS: 7443c4e0415SDaniel Scheller switch ((enum MXL_HYDRA_MODULATION_E) 7453c4e0415SDaniel Scheller reg_data[DMD_MODULATION_SCHEME_ADDR]) { 7463c4e0415SDaniel Scheller case MXL_HYDRA_MOD_QPSK: 7473c4e0415SDaniel Scheller p->modulation = QPSK; 7483c4e0415SDaniel Scheller break; 7493c4e0415SDaniel Scheller case MXL_HYDRA_MOD_8PSK: 7503c4e0415SDaniel Scheller p->modulation = PSK_8; 7513c4e0415SDaniel Scheller break; 7523c4e0415SDaniel Scheller default: 7533c4e0415SDaniel Scheller break; 7543c4e0415SDaniel Scheller } 7553c4e0415SDaniel Scheller switch ((enum MXL_HYDRA_ROLLOFF_E) 7563c4e0415SDaniel Scheller reg_data[DMD_SPECTRUM_ROLL_OFF_ADDR]) { 7573c4e0415SDaniel Scheller case MXL_HYDRA_ROLLOFF_0_20: 7583c4e0415SDaniel Scheller p->rolloff = ROLLOFF_20; 7593c4e0415SDaniel Scheller break; 7603c4e0415SDaniel Scheller case MXL_HYDRA_ROLLOFF_0_35: 7613c4e0415SDaniel Scheller p->rolloff = ROLLOFF_35; 7623c4e0415SDaniel Scheller break; 7633c4e0415SDaniel Scheller case MXL_HYDRA_ROLLOFF_0_25: 7643c4e0415SDaniel Scheller p->rolloff = ROLLOFF_25; 7653c4e0415SDaniel Scheller break; 7663c4e0415SDaniel Scheller default: 7673c4e0415SDaniel Scheller break; 7683c4e0415SDaniel Scheller } 7693c4e0415SDaniel Scheller break; 7703c4e0415SDaniel Scheller default: 7713c4e0415SDaniel Scheller return -EINVAL; 7723c4e0415SDaniel Scheller } 7733c4e0415SDaniel Scheller return 0; 7743c4e0415SDaniel Scheller } 7753c4e0415SDaniel Scheller 7763c4e0415SDaniel Scheller static int set_input(struct dvb_frontend *fe, int input) 7773c4e0415SDaniel Scheller { 7783c4e0415SDaniel Scheller struct mxl *state = fe->demodulator_priv; 7793c4e0415SDaniel Scheller 7803c4e0415SDaniel Scheller state->tuner = input; 7813c4e0415SDaniel Scheller return 0; 7823c4e0415SDaniel Scheller } 7833c4e0415SDaniel Scheller 784*28fc5a36SJulia Lawall static const struct dvb_frontend_ops mxl_ops = { 7853c4e0415SDaniel Scheller .delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS }, 7863c4e0415SDaniel Scheller .info = { 7873c4e0415SDaniel Scheller .name = "MaxLinear MxL5xx DVB-S/S2 tuner-demodulator", 788f1b1eabfSMauro Carvalho Chehab .frequency_min_hz = 300 * MHz, 789f1b1eabfSMauro Carvalho Chehab .frequency_max_hz = 2350 * MHz, 7903c4e0415SDaniel Scheller .symbol_rate_min = 1000000, 7913c4e0415SDaniel Scheller .symbol_rate_max = 45000000, 7923c4e0415SDaniel Scheller .caps = FE_CAN_INVERSION_AUTO | 7933c4e0415SDaniel Scheller FE_CAN_FEC_AUTO | 7943c4e0415SDaniel Scheller FE_CAN_QPSK | 7953c4e0415SDaniel Scheller FE_CAN_2G_MODULATION 7963c4e0415SDaniel Scheller }, 7973c4e0415SDaniel Scheller .init = init, 7983c4e0415SDaniel Scheller .release = release, 7993c4e0415SDaniel Scheller .get_frontend_algo = get_algo, 8003c4e0415SDaniel Scheller .tune = tune, 8013c4e0415SDaniel Scheller .read_status = read_status, 8023c4e0415SDaniel Scheller .sleep = sleep, 8033c4e0415SDaniel Scheller .get_frontend = get_frontend, 8043c4e0415SDaniel Scheller .diseqc_send_master_cmd = send_master_cmd, 8053c4e0415SDaniel Scheller }; 8063c4e0415SDaniel Scheller 8073c4e0415SDaniel Scheller static struct mxl_base *match_base(struct i2c_adapter *i2c, u8 adr) 8083c4e0415SDaniel Scheller { 8093c4e0415SDaniel Scheller struct mxl_base *p; 8103c4e0415SDaniel Scheller 8113c4e0415SDaniel Scheller list_for_each_entry(p, &mxllist, mxllist) 8123c4e0415SDaniel Scheller if (p->i2c == i2c && p->adr == adr) 8133c4e0415SDaniel Scheller return p; 8143c4e0415SDaniel Scheller return NULL; 8153c4e0415SDaniel Scheller } 8163c4e0415SDaniel Scheller 8173c4e0415SDaniel Scheller static void cfg_dev_xtal(struct mxl *state, u32 freq, u32 cap, u32 enable) 8183c4e0415SDaniel Scheller { 8193c4e0415SDaniel Scheller if (state->base->can_clkout || !enable) 8203c4e0415SDaniel Scheller update_by_mnemonic(state, 0x90200054, 23, 1, enable); 8213c4e0415SDaniel Scheller 8223c4e0415SDaniel Scheller if (freq == 24000000) 8233c4e0415SDaniel Scheller write_register(state, HYDRA_CRYSTAL_SETTING, 0); 8243c4e0415SDaniel Scheller else 8253c4e0415SDaniel Scheller write_register(state, HYDRA_CRYSTAL_SETTING, 1); 8263c4e0415SDaniel Scheller 8273c4e0415SDaniel Scheller write_register(state, HYDRA_CRYSTAL_CAP, cap); 8283c4e0415SDaniel Scheller } 8293c4e0415SDaniel Scheller 8303c4e0415SDaniel Scheller static u32 get_big_endian(u8 num_of_bits, const u8 buf[]) 8313c4e0415SDaniel Scheller { 8323c4e0415SDaniel Scheller u32 ret_value = 0; 8333c4e0415SDaniel Scheller 8343c4e0415SDaniel Scheller switch (num_of_bits) { 8353c4e0415SDaniel Scheller case 24: 8363c4e0415SDaniel Scheller ret_value = (((u32) buf[0]) << 16) | 8373c4e0415SDaniel Scheller (((u32) buf[1]) << 8) | buf[2]; 8383c4e0415SDaniel Scheller break; 8393c4e0415SDaniel Scheller case 32: 8403c4e0415SDaniel Scheller ret_value = (((u32) buf[0]) << 24) | 8413c4e0415SDaniel Scheller (((u32) buf[1]) << 16) | 8423c4e0415SDaniel Scheller (((u32) buf[2]) << 8) | buf[3]; 8433c4e0415SDaniel Scheller break; 8443c4e0415SDaniel Scheller default: 8453c4e0415SDaniel Scheller break; 8463c4e0415SDaniel Scheller } 8473c4e0415SDaniel Scheller 8483c4e0415SDaniel Scheller return ret_value; 8493c4e0415SDaniel Scheller } 8503c4e0415SDaniel Scheller 8513c4e0415SDaniel Scheller static int write_fw_segment(struct mxl *state, 8523c4e0415SDaniel Scheller u32 mem_addr, u32 total_size, u8 *data_ptr) 8533c4e0415SDaniel Scheller { 8543c4e0415SDaniel Scheller int status; 8553c4e0415SDaniel Scheller u32 data_count = 0; 8563c4e0415SDaniel Scheller u32 size = 0; 8573c4e0415SDaniel Scheller u32 orig_size = 0; 8583c4e0415SDaniel Scheller u8 *w_buf_ptr = NULL; 8593c4e0415SDaniel Scheller u32 block_size = ((MXL_HYDRA_OEM_MAX_BLOCK_WRITE_LENGTH - 8603c4e0415SDaniel Scheller (MXL_HYDRA_I2C_HDR_SIZE + 8613c4e0415SDaniel Scheller MXL_HYDRA_REG_SIZE_IN_BYTES)) / 4) * 4; 8623c4e0415SDaniel Scheller u8 w_msg_buffer[MXL_HYDRA_OEM_MAX_BLOCK_WRITE_LENGTH - 8633c4e0415SDaniel Scheller (MXL_HYDRA_I2C_HDR_SIZE + MXL_HYDRA_REG_SIZE_IN_BYTES)]; 8643c4e0415SDaniel Scheller 8653c4e0415SDaniel Scheller do { 8663c4e0415SDaniel Scheller size = orig_size = (((u32)(data_count + block_size)) > total_size) ? 8673c4e0415SDaniel Scheller (total_size - data_count) : block_size; 8683c4e0415SDaniel Scheller 8693c4e0415SDaniel Scheller if (orig_size & 3) 8703c4e0415SDaniel Scheller size = (orig_size + 4) & ~3; 8713c4e0415SDaniel Scheller w_buf_ptr = &w_msg_buffer[0]; 8723c4e0415SDaniel Scheller memset((void *) w_buf_ptr, 0, size); 8733c4e0415SDaniel Scheller memcpy((void *) w_buf_ptr, (void *) data_ptr, orig_size); 8743c4e0415SDaniel Scheller convert_endian(1, size, w_buf_ptr); 8753c4e0415SDaniel Scheller status = write_firmware_block(state, mem_addr, size, w_buf_ptr); 8763c4e0415SDaniel Scheller if (status) 8773c4e0415SDaniel Scheller return status; 8783c4e0415SDaniel Scheller data_count += size; 8793c4e0415SDaniel Scheller mem_addr += size; 8803c4e0415SDaniel Scheller data_ptr += size; 8813c4e0415SDaniel Scheller } while (data_count < total_size); 8823c4e0415SDaniel Scheller 8833c4e0415SDaniel Scheller return status; 8843c4e0415SDaniel Scheller } 8853c4e0415SDaniel Scheller 8863c4e0415SDaniel Scheller static int do_firmware_download(struct mxl *state, u8 *mbin_buffer_ptr, 8873c4e0415SDaniel Scheller u32 mbin_buffer_size) 8883c4e0415SDaniel Scheller 8893c4e0415SDaniel Scheller { 8903c4e0415SDaniel Scheller int status; 8913c4e0415SDaniel Scheller u32 index = 0; 8923c4e0415SDaniel Scheller u32 seg_length = 0; 8933c4e0415SDaniel Scheller u32 seg_address = 0; 8943c4e0415SDaniel Scheller struct MBIN_FILE_T *mbin_ptr = (struct MBIN_FILE_T *)mbin_buffer_ptr; 8953c4e0415SDaniel Scheller struct MBIN_SEGMENT_T *segment_ptr; 8963c4e0415SDaniel Scheller enum MXL_BOOL_E xcpu_fw_flag = MXL_FALSE; 8973c4e0415SDaniel Scheller 8983c4e0415SDaniel Scheller if (mbin_ptr->header.id != MBIN_FILE_HEADER_ID) { 8993c4e0415SDaniel Scheller dev_err(state->i2cdev, "%s: Invalid file header ID (%c)\n", 9003c4e0415SDaniel Scheller __func__, mbin_ptr->header.id); 9013c4e0415SDaniel Scheller return -EINVAL; 9023c4e0415SDaniel Scheller } 9033c4e0415SDaniel Scheller status = write_register(state, FW_DL_SIGN_ADDR, 0); 9043c4e0415SDaniel Scheller if (status) 9053c4e0415SDaniel Scheller return status; 9063c4e0415SDaniel Scheller segment_ptr = (struct MBIN_SEGMENT_T *) (&mbin_ptr->data[0]); 9073c4e0415SDaniel Scheller for (index = 0; index < mbin_ptr->header.num_segments; index++) { 9083c4e0415SDaniel Scheller if (segment_ptr->header.id != MBIN_SEGMENT_HEADER_ID) { 9093c4e0415SDaniel Scheller dev_err(state->i2cdev, "%s: Invalid segment header ID (%c)\n", 9103c4e0415SDaniel Scheller __func__, segment_ptr->header.id); 9113c4e0415SDaniel Scheller return -EINVAL; 9123c4e0415SDaniel Scheller } 9133c4e0415SDaniel Scheller seg_length = get_big_endian(24, 9143c4e0415SDaniel Scheller &(segment_ptr->header.len24[0])); 9153c4e0415SDaniel Scheller seg_address = get_big_endian(32, 9163c4e0415SDaniel Scheller &(segment_ptr->header.address[0])); 9173c4e0415SDaniel Scheller 9183c4e0415SDaniel Scheller if (state->base->type == MXL_HYDRA_DEVICE_568) { 9193c4e0415SDaniel Scheller if ((((seg_address & 0x90760000) == 0x90760000) || 9203c4e0415SDaniel Scheller ((seg_address & 0x90740000) == 0x90740000)) && 9213c4e0415SDaniel Scheller (xcpu_fw_flag == MXL_FALSE)) { 9223c4e0415SDaniel Scheller update_by_mnemonic(state, 0x8003003C, 0, 1, 1); 9233c4e0415SDaniel Scheller msleep(200); 9243c4e0415SDaniel Scheller write_register(state, 0x90720000, 0); 9253c4e0415SDaniel Scheller usleep_range(10000, 11000); 9263c4e0415SDaniel Scheller xcpu_fw_flag = MXL_TRUE; 9273c4e0415SDaniel Scheller } 9283c4e0415SDaniel Scheller status = write_fw_segment(state, seg_address, 9293c4e0415SDaniel Scheller seg_length, 9303c4e0415SDaniel Scheller (u8 *) segment_ptr->data); 9313c4e0415SDaniel Scheller } else { 9323c4e0415SDaniel Scheller if (((seg_address & 0x90760000) != 0x90760000) && 9333c4e0415SDaniel Scheller ((seg_address & 0x90740000) != 0x90740000)) 9343c4e0415SDaniel Scheller status = write_fw_segment(state, seg_address, 9353c4e0415SDaniel Scheller seg_length, (u8 *) segment_ptr->data); 9363c4e0415SDaniel Scheller } 9373c4e0415SDaniel Scheller if (status) 9383c4e0415SDaniel Scheller return status; 9393c4e0415SDaniel Scheller segment_ptr = (struct MBIN_SEGMENT_T *) 9403c4e0415SDaniel Scheller &(segment_ptr->data[((seg_length + 3) / 4) * 4]); 9413c4e0415SDaniel Scheller } 9423c4e0415SDaniel Scheller return status; 9433c4e0415SDaniel Scheller } 9443c4e0415SDaniel Scheller 9453c4e0415SDaniel Scheller static int check_fw(struct mxl *state, u8 *mbin, u32 mbin_len) 9463c4e0415SDaniel Scheller { 9473c4e0415SDaniel Scheller struct MBIN_FILE_HEADER_T *fh = (struct MBIN_FILE_HEADER_T *) mbin; 9483c4e0415SDaniel Scheller u32 flen = (fh->image_size24[0] << 16) | 9493c4e0415SDaniel Scheller (fh->image_size24[1] << 8) | fh->image_size24[2]; 9503c4e0415SDaniel Scheller u8 *fw, cs = 0; 9513c4e0415SDaniel Scheller u32 i; 9523c4e0415SDaniel Scheller 9533c4e0415SDaniel Scheller if (fh->id != 'M' || fh->fmt_version != '1' || flen > 0x3FFF0) { 9543c4e0415SDaniel Scheller dev_info(state->i2cdev, "Invalid FW Header\n"); 9553c4e0415SDaniel Scheller return -1; 9563c4e0415SDaniel Scheller } 9573c4e0415SDaniel Scheller fw = mbin + sizeof(struct MBIN_FILE_HEADER_T); 9583c4e0415SDaniel Scheller for (i = 0; i < flen; i += 1) 9593c4e0415SDaniel Scheller cs += fw[i]; 9603c4e0415SDaniel Scheller if (cs != fh->image_checksum) { 9613c4e0415SDaniel Scheller dev_info(state->i2cdev, "Invalid FW Checksum\n"); 9623c4e0415SDaniel Scheller return -1; 9633c4e0415SDaniel Scheller } 9643c4e0415SDaniel Scheller return 0; 9653c4e0415SDaniel Scheller } 9663c4e0415SDaniel Scheller 9673c4e0415SDaniel Scheller static int firmware_download(struct mxl *state, u8 *mbin, u32 mbin_len) 9683c4e0415SDaniel Scheller { 9693c4e0415SDaniel Scheller int status; 9703c4e0415SDaniel Scheller u32 reg_data = 0; 9713c4e0415SDaniel Scheller struct MXL_HYDRA_SKU_COMMAND_T dev_sku_cfg; 9723c4e0415SDaniel Scheller u8 cmd_size = sizeof(struct MXL_HYDRA_SKU_COMMAND_T); 9733c4e0415SDaniel Scheller u8 cmd_buff[sizeof(struct MXL_HYDRA_SKU_COMMAND_T) + 6]; 9743c4e0415SDaniel Scheller 9753c4e0415SDaniel Scheller if (check_fw(state, mbin, mbin_len)) 9763c4e0415SDaniel Scheller return -1; 9773c4e0415SDaniel Scheller 9783c4e0415SDaniel Scheller /* put CPU into reset */ 9793c4e0415SDaniel Scheller status = update_by_mnemonic(state, 0x8003003C, 0, 1, 0); 9803c4e0415SDaniel Scheller if (status) 9813c4e0415SDaniel Scheller return status; 9823c4e0415SDaniel Scheller usleep_range(1000, 2000); 9833c4e0415SDaniel Scheller 9843c4e0415SDaniel Scheller /* Reset TX FIFO's, BBAND, XBAR */ 9853c4e0415SDaniel Scheller status = write_register(state, HYDRA_RESET_TRANSPORT_FIFO_REG, 9863c4e0415SDaniel Scheller HYDRA_RESET_TRANSPORT_FIFO_DATA); 9873c4e0415SDaniel Scheller if (status) 9883c4e0415SDaniel Scheller return status; 9893c4e0415SDaniel Scheller status = write_register(state, HYDRA_RESET_BBAND_REG, 9903c4e0415SDaniel Scheller HYDRA_RESET_BBAND_DATA); 9913c4e0415SDaniel Scheller if (status) 9923c4e0415SDaniel Scheller return status; 9933c4e0415SDaniel Scheller status = write_register(state, HYDRA_RESET_XBAR_REG, 9943c4e0415SDaniel Scheller HYDRA_RESET_XBAR_DATA); 9953c4e0415SDaniel Scheller if (status) 9963c4e0415SDaniel Scheller return status; 9973c4e0415SDaniel Scheller 9983c4e0415SDaniel Scheller /* Disable clock to Baseband, Wideband, SerDes, 9993c4e0415SDaniel Scheller * Alias ext & Transport modules 10003c4e0415SDaniel Scheller */ 10013c4e0415SDaniel Scheller status = write_register(state, HYDRA_MODULES_CLK_2_REG, 10023c4e0415SDaniel Scheller HYDRA_DISABLE_CLK_2); 10033c4e0415SDaniel Scheller if (status) 10043c4e0415SDaniel Scheller return status; 10053c4e0415SDaniel Scheller /* Clear Software & Host interrupt status - (Clear on read) */ 10063c4e0415SDaniel Scheller status = read_register(state, HYDRA_PRCM_ROOT_CLK_REG, ®_data); 10073c4e0415SDaniel Scheller if (status) 10083c4e0415SDaniel Scheller return status; 10093c4e0415SDaniel Scheller status = do_firmware_download(state, mbin, mbin_len); 10103c4e0415SDaniel Scheller if (status) 10113c4e0415SDaniel Scheller return status; 10123c4e0415SDaniel Scheller 10133c4e0415SDaniel Scheller if (state->base->type == MXL_HYDRA_DEVICE_568) { 10143c4e0415SDaniel Scheller usleep_range(10000, 11000); 10153c4e0415SDaniel Scheller 10163c4e0415SDaniel Scheller /* bring XCPU out of reset */ 10173c4e0415SDaniel Scheller status = write_register(state, 0x90720000, 1); 10183c4e0415SDaniel Scheller if (status) 10193c4e0415SDaniel Scheller return status; 10203c4e0415SDaniel Scheller msleep(500); 10213c4e0415SDaniel Scheller 10223c4e0415SDaniel Scheller /* Enable XCPU UART message processing in MCPU */ 10233c4e0415SDaniel Scheller status = write_register(state, 0x9076B510, 1); 10243c4e0415SDaniel Scheller if (status) 10253c4e0415SDaniel Scheller return status; 10263c4e0415SDaniel Scheller } else { 10273c4e0415SDaniel Scheller /* Bring CPU out of reset */ 10283c4e0415SDaniel Scheller status = update_by_mnemonic(state, 0x8003003C, 0, 1, 1); 10293c4e0415SDaniel Scheller if (status) 10303c4e0415SDaniel Scheller return status; 10313c4e0415SDaniel Scheller /* Wait until FW boots */ 10323c4e0415SDaniel Scheller msleep(150); 10333c4e0415SDaniel Scheller } 10343c4e0415SDaniel Scheller 10353c4e0415SDaniel Scheller /* Initialize XPT XBAR */ 10363c4e0415SDaniel Scheller status = write_register(state, XPT_DMD0_BASEADDR, 0x76543210); 10373c4e0415SDaniel Scheller if (status) 10383c4e0415SDaniel Scheller return status; 10393c4e0415SDaniel Scheller 10403c4e0415SDaniel Scheller if (!firmware_is_alive(state)) 10413c4e0415SDaniel Scheller return -1; 10423c4e0415SDaniel Scheller 10433c4e0415SDaniel Scheller dev_info(state->i2cdev, "Hydra FW alive. Hail!\n"); 10443c4e0415SDaniel Scheller 10453c4e0415SDaniel Scheller /* sometimes register values are wrong shortly 10463c4e0415SDaniel Scheller * after first heart beats 10473c4e0415SDaniel Scheller */ 10483c4e0415SDaniel Scheller msleep(50); 10493c4e0415SDaniel Scheller 10503c4e0415SDaniel Scheller dev_sku_cfg.sku_type = state->base->sku_type; 10513c4e0415SDaniel Scheller BUILD_HYDRA_CMD(MXL_HYDRA_DEV_CFG_SKU_CMD, MXL_CMD_WRITE, 10523c4e0415SDaniel Scheller cmd_size, &dev_sku_cfg, cmd_buff); 10533c4e0415SDaniel Scheller status = send_command(state, cmd_size + MXL_HYDRA_CMD_HEADER_SIZE, 10543c4e0415SDaniel Scheller &cmd_buff[0]); 10553c4e0415SDaniel Scheller 10563c4e0415SDaniel Scheller return status; 10573c4e0415SDaniel Scheller } 10583c4e0415SDaniel Scheller 10593c4e0415SDaniel Scheller static int cfg_ts_pad_mux(struct mxl *state, enum MXL_BOOL_E enable_serial_ts) 10603c4e0415SDaniel Scheller { 10613c4e0415SDaniel Scheller int status = 0; 10623c4e0415SDaniel Scheller u32 pad_mux_value = 0; 10633c4e0415SDaniel Scheller 10643c4e0415SDaniel Scheller if (enable_serial_ts == MXL_TRUE) { 10653c4e0415SDaniel Scheller pad_mux_value = 0; 10663c4e0415SDaniel Scheller if ((state->base->type == MXL_HYDRA_DEVICE_541) || 10673c4e0415SDaniel Scheller (state->base->type == MXL_HYDRA_DEVICE_541S)) 10683c4e0415SDaniel Scheller pad_mux_value = 2; 10693c4e0415SDaniel Scheller } else { 10703c4e0415SDaniel Scheller if ((state->base->type == MXL_HYDRA_DEVICE_581) || 10713c4e0415SDaniel Scheller (state->base->type == MXL_HYDRA_DEVICE_581S)) 10723c4e0415SDaniel Scheller pad_mux_value = 2; 10733c4e0415SDaniel Scheller else 10743c4e0415SDaniel Scheller pad_mux_value = 3; 10753c4e0415SDaniel Scheller } 10763c4e0415SDaniel Scheller 10773c4e0415SDaniel Scheller switch (state->base->type) { 10783c4e0415SDaniel Scheller case MXL_HYDRA_DEVICE_561: 10793c4e0415SDaniel Scheller case MXL_HYDRA_DEVICE_581: 10803c4e0415SDaniel Scheller case MXL_HYDRA_DEVICE_541: 10813c4e0415SDaniel Scheller case MXL_HYDRA_DEVICE_541S: 10823c4e0415SDaniel Scheller case MXL_HYDRA_DEVICE_561S: 10833c4e0415SDaniel Scheller case MXL_HYDRA_DEVICE_581S: 10843c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 0x90000170, 24, 3, 10853c4e0415SDaniel Scheller pad_mux_value); 10863c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 0x90000170, 28, 3, 10873c4e0415SDaniel Scheller pad_mux_value); 10883c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 0x90000174, 0, 3, 10893c4e0415SDaniel Scheller pad_mux_value); 10903c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 0x90000174, 4, 3, 10913c4e0415SDaniel Scheller pad_mux_value); 10923c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 0x90000174, 8, 3, 10933c4e0415SDaniel Scheller pad_mux_value); 10943c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 0x90000174, 12, 3, 10953c4e0415SDaniel Scheller pad_mux_value); 10963c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 0x90000174, 16, 3, 10973c4e0415SDaniel Scheller pad_mux_value); 10983c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 0x90000174, 20, 3, 10993c4e0415SDaniel Scheller pad_mux_value); 11003c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 0x90000174, 24, 3, 11013c4e0415SDaniel Scheller pad_mux_value); 11023c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 0x90000174, 28, 3, 11033c4e0415SDaniel Scheller pad_mux_value); 11043c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 0x90000178, 0, 3, 11053c4e0415SDaniel Scheller pad_mux_value); 11063c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 0x90000178, 4, 3, 11073c4e0415SDaniel Scheller pad_mux_value); 11083c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 0x90000178, 8, 3, 11093c4e0415SDaniel Scheller pad_mux_value); 11103c4e0415SDaniel Scheller break; 11113c4e0415SDaniel Scheller 11123c4e0415SDaniel Scheller case MXL_HYDRA_DEVICE_544: 11133c4e0415SDaniel Scheller case MXL_HYDRA_DEVICE_542: 11143c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 0x9000016C, 4, 3, 1); 11153c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 0x9000016C, 8, 3, 0); 11163c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 0x9000016C, 12, 3, 0); 11173c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 0x9000016C, 16, 3, 0); 11183c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 0x90000170, 0, 3, 0); 11193c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 0x90000178, 12, 3, 1); 11203c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 0x90000178, 16, 3, 1); 11213c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 0x90000178, 20, 3, 1); 11223c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 0x90000178, 24, 3, 1); 11233c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 0x9000017C, 0, 3, 1); 11243c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 0x9000017C, 4, 3, 1); 11253c4e0415SDaniel Scheller if (enable_serial_ts == MXL_ENABLE) { 11263c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11273c4e0415SDaniel Scheller 0x90000170, 4, 3, 0); 11283c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11293c4e0415SDaniel Scheller 0x90000170, 8, 3, 0); 11303c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11313c4e0415SDaniel Scheller 0x90000170, 12, 3, 0); 11323c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11333c4e0415SDaniel Scheller 0x90000170, 16, 3, 0); 11343c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11353c4e0415SDaniel Scheller 0x90000170, 20, 3, 1); 11363c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11373c4e0415SDaniel Scheller 0x90000170, 24, 3, 1); 11383c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11393c4e0415SDaniel Scheller 0x90000170, 28, 3, 2); 11403c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11413c4e0415SDaniel Scheller 0x90000174, 0, 3, 2); 11423c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11433c4e0415SDaniel Scheller 0x90000174, 4, 3, 2); 11443c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11453c4e0415SDaniel Scheller 0x90000174, 8, 3, 2); 11463c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11473c4e0415SDaniel Scheller 0x90000174, 12, 3, 2); 11483c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11493c4e0415SDaniel Scheller 0x90000174, 16, 3, 2); 11503c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11513c4e0415SDaniel Scheller 0x90000174, 20, 3, 2); 11523c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11533c4e0415SDaniel Scheller 0x90000174, 24, 3, 2); 11543c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11553c4e0415SDaniel Scheller 0x90000174, 28, 3, 2); 11563c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11573c4e0415SDaniel Scheller 0x90000178, 0, 3, 2); 11583c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11593c4e0415SDaniel Scheller 0x90000178, 4, 3, 2); 11603c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11613c4e0415SDaniel Scheller 0x90000178, 8, 3, 2); 11623c4e0415SDaniel Scheller } else { 11633c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11643c4e0415SDaniel Scheller 0x90000170, 4, 3, 3); 11653c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11663c4e0415SDaniel Scheller 0x90000170, 8, 3, 3); 11673c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11683c4e0415SDaniel Scheller 0x90000170, 12, 3, 3); 11693c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11703c4e0415SDaniel Scheller 0x90000170, 16, 3, 3); 11713c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11723c4e0415SDaniel Scheller 0x90000170, 20, 3, 3); 11733c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11743c4e0415SDaniel Scheller 0x90000170, 24, 3, 3); 11753c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11763c4e0415SDaniel Scheller 0x90000170, 28, 3, 3); 11773c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11783c4e0415SDaniel Scheller 0x90000174, 0, 3, 3); 11793c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11803c4e0415SDaniel Scheller 0x90000174, 4, 3, 3); 11813c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11823c4e0415SDaniel Scheller 0x90000174, 8, 3, 3); 11833c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11843c4e0415SDaniel Scheller 0x90000174, 12, 3, 3); 11853c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11863c4e0415SDaniel Scheller 0x90000174, 16, 3, 3); 11873c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11883c4e0415SDaniel Scheller 0x90000174, 20, 3, 1); 11893c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11903c4e0415SDaniel Scheller 0x90000174, 24, 3, 1); 11913c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11923c4e0415SDaniel Scheller 0x90000174, 28, 3, 1); 11933c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11943c4e0415SDaniel Scheller 0x90000178, 0, 3, 1); 11953c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11963c4e0415SDaniel Scheller 0x90000178, 4, 3, 1); 11973c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 11983c4e0415SDaniel Scheller 0x90000178, 8, 3, 1); 11993c4e0415SDaniel Scheller } 12003c4e0415SDaniel Scheller break; 12013c4e0415SDaniel Scheller 12023c4e0415SDaniel Scheller case MXL_HYDRA_DEVICE_568: 12033c4e0415SDaniel Scheller if (enable_serial_ts == MXL_FALSE) { 12043c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12053c4e0415SDaniel Scheller 0x9000016C, 8, 3, 5); 12063c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12073c4e0415SDaniel Scheller 0x9000016C, 12, 3, 5); 12083c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12093c4e0415SDaniel Scheller 0x9000016C, 16, 3, 5); 12103c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12113c4e0415SDaniel Scheller 0x9000016C, 20, 3, 5); 12123c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12133c4e0415SDaniel Scheller 0x9000016C, 24, 3, 5); 12143c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12153c4e0415SDaniel Scheller 0x9000016C, 28, 3, 5); 12163c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12173c4e0415SDaniel Scheller 0x90000170, 0, 3, 5); 12183c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12193c4e0415SDaniel Scheller 0x90000170, 4, 3, 5); 12203c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12213c4e0415SDaniel Scheller 0x90000170, 8, 3, 5); 12223c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12233c4e0415SDaniel Scheller 0x90000170, 12, 3, 5); 12243c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12253c4e0415SDaniel Scheller 0x90000170, 16, 3, 5); 12263c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12273c4e0415SDaniel Scheller 0x90000170, 20, 3, 5); 12283c4e0415SDaniel Scheller 12293c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12303c4e0415SDaniel Scheller 0x90000170, 24, 3, pad_mux_value); 12313c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12323c4e0415SDaniel Scheller 0x90000174, 0, 3, pad_mux_value); 12333c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12343c4e0415SDaniel Scheller 0x90000174, 4, 3, pad_mux_value); 12353c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12363c4e0415SDaniel Scheller 0x90000174, 8, 3, pad_mux_value); 12373c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12383c4e0415SDaniel Scheller 0x90000174, 12, 3, pad_mux_value); 12393c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12403c4e0415SDaniel Scheller 0x90000174, 16, 3, pad_mux_value); 12413c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12423c4e0415SDaniel Scheller 0x90000174, 20, 3, pad_mux_value); 12433c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12443c4e0415SDaniel Scheller 0x90000174, 24, 3, pad_mux_value); 12453c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12463c4e0415SDaniel Scheller 0x90000174, 28, 3, pad_mux_value); 12473c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12483c4e0415SDaniel Scheller 0x90000178, 0, 3, pad_mux_value); 12493c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12503c4e0415SDaniel Scheller 0x90000178, 4, 3, pad_mux_value); 12513c4e0415SDaniel Scheller 12523c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12533c4e0415SDaniel Scheller 0x90000178, 8, 3, 5); 12543c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12553c4e0415SDaniel Scheller 0x90000178, 12, 3, 5); 12563c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12573c4e0415SDaniel Scheller 0x90000178, 16, 3, 5); 12583c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12593c4e0415SDaniel Scheller 0x90000178, 20, 3, 5); 12603c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12613c4e0415SDaniel Scheller 0x90000178, 24, 3, 5); 12623c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12633c4e0415SDaniel Scheller 0x90000178, 28, 3, 5); 12643c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12653c4e0415SDaniel Scheller 0x9000017C, 0, 3, 5); 12663c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12673c4e0415SDaniel Scheller 0x9000017C, 4, 3, 5); 12683c4e0415SDaniel Scheller } else { 12693c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12703c4e0415SDaniel Scheller 0x90000170, 4, 3, pad_mux_value); 12713c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12723c4e0415SDaniel Scheller 0x90000170, 8, 3, pad_mux_value); 12733c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12743c4e0415SDaniel Scheller 0x90000170, 12, 3, pad_mux_value); 12753c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12763c4e0415SDaniel Scheller 0x90000170, 16, 3, pad_mux_value); 12773c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12783c4e0415SDaniel Scheller 0x90000170, 20, 3, pad_mux_value); 12793c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12803c4e0415SDaniel Scheller 0x90000170, 24, 3, pad_mux_value); 12813c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12823c4e0415SDaniel Scheller 0x90000170, 28, 3, pad_mux_value); 12833c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12843c4e0415SDaniel Scheller 0x90000174, 0, 3, pad_mux_value); 12853c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12863c4e0415SDaniel Scheller 0x90000174, 4, 3, pad_mux_value); 12873c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12883c4e0415SDaniel Scheller 0x90000174, 8, 3, pad_mux_value); 12893c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12903c4e0415SDaniel Scheller 0x90000174, 12, 3, pad_mux_value); 12913c4e0415SDaniel Scheller } 12923c4e0415SDaniel Scheller break; 12933c4e0415SDaniel Scheller 12943c4e0415SDaniel Scheller 12953c4e0415SDaniel Scheller case MXL_HYDRA_DEVICE_584: 12963c4e0415SDaniel Scheller default: 12973c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 12983c4e0415SDaniel Scheller 0x90000170, 4, 3, pad_mux_value); 12993c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 13003c4e0415SDaniel Scheller 0x90000170, 8, 3, pad_mux_value); 13013c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 13023c4e0415SDaniel Scheller 0x90000170, 12, 3, pad_mux_value); 13033c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 13043c4e0415SDaniel Scheller 0x90000170, 16, 3, pad_mux_value); 13053c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 13063c4e0415SDaniel Scheller 0x90000170, 20, 3, pad_mux_value); 13073c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 13083c4e0415SDaniel Scheller 0x90000170, 24, 3, pad_mux_value); 13093c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 13103c4e0415SDaniel Scheller 0x90000170, 28, 3, pad_mux_value); 13113c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 13123c4e0415SDaniel Scheller 0x90000174, 0, 3, pad_mux_value); 13133c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 13143c4e0415SDaniel Scheller 0x90000174, 4, 3, pad_mux_value); 13153c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 13163c4e0415SDaniel Scheller 0x90000174, 8, 3, pad_mux_value); 13173c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 13183c4e0415SDaniel Scheller 0x90000174, 12, 3, pad_mux_value); 13193c4e0415SDaniel Scheller break; 13203c4e0415SDaniel Scheller } 13213c4e0415SDaniel Scheller return status; 13223c4e0415SDaniel Scheller } 13233c4e0415SDaniel Scheller 13243c4e0415SDaniel Scheller static int set_drive_strength(struct mxl *state, 13253c4e0415SDaniel Scheller enum MXL_HYDRA_TS_DRIVE_STRENGTH_E ts_drive_strength) 13263c4e0415SDaniel Scheller { 13273c4e0415SDaniel Scheller int stat = 0; 13283c4e0415SDaniel Scheller u32 val; 13293c4e0415SDaniel Scheller 13303c4e0415SDaniel Scheller read_register(state, 0x90000194, &val); 13313c4e0415SDaniel Scheller dev_info(state->i2cdev, "DIGIO = %08x\n", val); 13323c4e0415SDaniel Scheller dev_info(state->i2cdev, "set drive_strength = %u\n", ts_drive_strength); 13333c4e0415SDaniel Scheller 13343c4e0415SDaniel Scheller 13353c4e0415SDaniel Scheller stat |= update_by_mnemonic(state, 0x90000194, 0, 3, ts_drive_strength); 13363c4e0415SDaniel Scheller stat |= update_by_mnemonic(state, 0x90000194, 20, 3, ts_drive_strength); 13373c4e0415SDaniel Scheller stat |= update_by_mnemonic(state, 0x90000194, 24, 3, ts_drive_strength); 13383c4e0415SDaniel Scheller stat |= update_by_mnemonic(state, 0x90000198, 12, 3, ts_drive_strength); 13393c4e0415SDaniel Scheller stat |= update_by_mnemonic(state, 0x90000198, 16, 3, ts_drive_strength); 13403c4e0415SDaniel Scheller stat |= update_by_mnemonic(state, 0x90000198, 20, 3, ts_drive_strength); 13413c4e0415SDaniel Scheller stat |= update_by_mnemonic(state, 0x90000198, 24, 3, ts_drive_strength); 13423c4e0415SDaniel Scheller stat |= update_by_mnemonic(state, 0x9000019C, 0, 3, ts_drive_strength); 13433c4e0415SDaniel Scheller stat |= update_by_mnemonic(state, 0x9000019C, 4, 3, ts_drive_strength); 13443c4e0415SDaniel Scheller stat |= update_by_mnemonic(state, 0x9000019C, 8, 3, ts_drive_strength); 13453c4e0415SDaniel Scheller stat |= update_by_mnemonic(state, 0x9000019C, 24, 3, ts_drive_strength); 13463c4e0415SDaniel Scheller stat |= update_by_mnemonic(state, 0x9000019C, 28, 3, ts_drive_strength); 13473c4e0415SDaniel Scheller stat |= update_by_mnemonic(state, 0x900001A0, 0, 3, ts_drive_strength); 13483c4e0415SDaniel Scheller stat |= update_by_mnemonic(state, 0x900001A0, 4, 3, ts_drive_strength); 13493c4e0415SDaniel Scheller stat |= update_by_mnemonic(state, 0x900001A0, 20, 3, ts_drive_strength); 13503c4e0415SDaniel Scheller stat |= update_by_mnemonic(state, 0x900001A0, 24, 3, ts_drive_strength); 13513c4e0415SDaniel Scheller stat |= update_by_mnemonic(state, 0x900001A0, 28, 3, ts_drive_strength); 13523c4e0415SDaniel Scheller 13533c4e0415SDaniel Scheller return stat; 13543c4e0415SDaniel Scheller } 13553c4e0415SDaniel Scheller 13563c4e0415SDaniel Scheller static int enable_tuner(struct mxl *state, u32 tuner, u32 enable) 13573c4e0415SDaniel Scheller { 13583c4e0415SDaniel Scheller int stat = 0; 13593c4e0415SDaniel Scheller struct MXL_HYDRA_TUNER_CMD ctrl_tuner_cmd; 13603c4e0415SDaniel Scheller u8 cmd_size = sizeof(ctrl_tuner_cmd); 13613c4e0415SDaniel Scheller u8 cmd_buff[MXL_HYDRA_OEM_MAX_CMD_BUFF_LEN]; 13623c4e0415SDaniel Scheller u32 val, count = 10; 13633c4e0415SDaniel Scheller 13643c4e0415SDaniel Scheller ctrl_tuner_cmd.tuner_id = tuner; 13653c4e0415SDaniel Scheller ctrl_tuner_cmd.enable = enable; 13663c4e0415SDaniel Scheller BUILD_HYDRA_CMD(MXL_HYDRA_TUNER_ACTIVATE_CMD, MXL_CMD_WRITE, 13673c4e0415SDaniel Scheller cmd_size, &ctrl_tuner_cmd, cmd_buff); 13683c4e0415SDaniel Scheller stat = send_command(state, cmd_size + MXL_HYDRA_CMD_HEADER_SIZE, 13693c4e0415SDaniel Scheller &cmd_buff[0]); 13703c4e0415SDaniel Scheller if (stat) 13713c4e0415SDaniel Scheller return stat; 13723c4e0415SDaniel Scheller read_register(state, HYDRA_TUNER_ENABLE_COMPLETE, &val); 13733c4e0415SDaniel Scheller while (--count && ((val >> tuner) & 1) != enable) { 13743c4e0415SDaniel Scheller msleep(20); 13753c4e0415SDaniel Scheller read_register(state, HYDRA_TUNER_ENABLE_COMPLETE, &val); 13763c4e0415SDaniel Scheller } 13773c4e0415SDaniel Scheller if (!count) 13783c4e0415SDaniel Scheller return -1; 13793c4e0415SDaniel Scheller read_register(state, HYDRA_TUNER_ENABLE_COMPLETE, &val); 13803c4e0415SDaniel Scheller dev_dbg(state->i2cdev, "tuner %u ready = %u\n", 13813c4e0415SDaniel Scheller tuner, (val >> tuner) & 1); 13823c4e0415SDaniel Scheller 13833c4e0415SDaniel Scheller return 0; 13843c4e0415SDaniel Scheller } 13853c4e0415SDaniel Scheller 13863c4e0415SDaniel Scheller 13873c4e0415SDaniel Scheller static int config_ts(struct mxl *state, enum MXL_HYDRA_DEMOD_ID_E demod_id, 13883c4e0415SDaniel Scheller struct MXL_HYDRA_MPEGOUT_PARAM_T *mpeg_out_param_ptr) 13893c4e0415SDaniel Scheller { 13903c4e0415SDaniel Scheller int status = 0; 13913c4e0415SDaniel Scheller u32 nco_count_min = 0; 13923c4e0415SDaniel Scheller u32 clk_type = 0; 13933c4e0415SDaniel Scheller 13943c4e0415SDaniel Scheller struct MXL_REG_FIELD_T xpt_sync_polarity[MXL_HYDRA_DEMOD_MAX] = { 13953c4e0415SDaniel Scheller {0x90700010, 8, 1}, {0x90700010, 9, 1}, 13963c4e0415SDaniel Scheller {0x90700010, 10, 1}, {0x90700010, 11, 1}, 13973c4e0415SDaniel Scheller {0x90700010, 12, 1}, {0x90700010, 13, 1}, 13983c4e0415SDaniel Scheller {0x90700010, 14, 1}, {0x90700010, 15, 1} }; 13993c4e0415SDaniel Scheller struct MXL_REG_FIELD_T xpt_clock_polarity[MXL_HYDRA_DEMOD_MAX] = { 14003c4e0415SDaniel Scheller {0x90700010, 16, 1}, {0x90700010, 17, 1}, 14013c4e0415SDaniel Scheller {0x90700010, 18, 1}, {0x90700010, 19, 1}, 14023c4e0415SDaniel Scheller {0x90700010, 20, 1}, {0x90700010, 21, 1}, 14033c4e0415SDaniel Scheller {0x90700010, 22, 1}, {0x90700010, 23, 1} }; 14043c4e0415SDaniel Scheller struct MXL_REG_FIELD_T xpt_valid_polarity[MXL_HYDRA_DEMOD_MAX] = { 14053c4e0415SDaniel Scheller {0x90700014, 0, 1}, {0x90700014, 1, 1}, 14063c4e0415SDaniel Scheller {0x90700014, 2, 1}, {0x90700014, 3, 1}, 14073c4e0415SDaniel Scheller {0x90700014, 4, 1}, {0x90700014, 5, 1}, 14083c4e0415SDaniel Scheller {0x90700014, 6, 1}, {0x90700014, 7, 1} }; 14093c4e0415SDaniel Scheller struct MXL_REG_FIELD_T xpt_ts_clock_phase[MXL_HYDRA_DEMOD_MAX] = { 14103c4e0415SDaniel Scheller {0x90700018, 0, 3}, {0x90700018, 4, 3}, 14113c4e0415SDaniel Scheller {0x90700018, 8, 3}, {0x90700018, 12, 3}, 14123c4e0415SDaniel Scheller {0x90700018, 16, 3}, {0x90700018, 20, 3}, 14133c4e0415SDaniel Scheller {0x90700018, 24, 3}, {0x90700018, 28, 3} }; 14143c4e0415SDaniel Scheller struct MXL_REG_FIELD_T xpt_lsb_first[MXL_HYDRA_DEMOD_MAX] = { 14153c4e0415SDaniel Scheller {0x9070000C, 16, 1}, {0x9070000C, 17, 1}, 14163c4e0415SDaniel Scheller {0x9070000C, 18, 1}, {0x9070000C, 19, 1}, 14173c4e0415SDaniel Scheller {0x9070000C, 20, 1}, {0x9070000C, 21, 1}, 14183c4e0415SDaniel Scheller {0x9070000C, 22, 1}, {0x9070000C, 23, 1} }; 14193c4e0415SDaniel Scheller struct MXL_REG_FIELD_T xpt_sync_byte[MXL_HYDRA_DEMOD_MAX] = { 14203c4e0415SDaniel Scheller {0x90700010, 0, 1}, {0x90700010, 1, 1}, 14213c4e0415SDaniel Scheller {0x90700010, 2, 1}, {0x90700010, 3, 1}, 14223c4e0415SDaniel Scheller {0x90700010, 4, 1}, {0x90700010, 5, 1}, 14233c4e0415SDaniel Scheller {0x90700010, 6, 1}, {0x90700010, 7, 1} }; 14243c4e0415SDaniel Scheller struct MXL_REG_FIELD_T xpt_enable_output[MXL_HYDRA_DEMOD_MAX] = { 14253c4e0415SDaniel Scheller {0x9070000C, 0, 1}, {0x9070000C, 1, 1}, 14263c4e0415SDaniel Scheller {0x9070000C, 2, 1}, {0x9070000C, 3, 1}, 14273c4e0415SDaniel Scheller {0x9070000C, 4, 1}, {0x9070000C, 5, 1}, 14283c4e0415SDaniel Scheller {0x9070000C, 6, 1}, {0x9070000C, 7, 1} }; 14293c4e0415SDaniel Scheller struct MXL_REG_FIELD_T xpt_err_replace_sync[MXL_HYDRA_DEMOD_MAX] = { 14303c4e0415SDaniel Scheller {0x9070000C, 24, 1}, {0x9070000C, 25, 1}, 14313c4e0415SDaniel Scheller {0x9070000C, 26, 1}, {0x9070000C, 27, 1}, 14323c4e0415SDaniel Scheller {0x9070000C, 28, 1}, {0x9070000C, 29, 1}, 14333c4e0415SDaniel Scheller {0x9070000C, 30, 1}, {0x9070000C, 31, 1} }; 14343c4e0415SDaniel Scheller struct MXL_REG_FIELD_T xpt_err_replace_valid[MXL_HYDRA_DEMOD_MAX] = { 14353c4e0415SDaniel Scheller {0x90700014, 8, 1}, {0x90700014, 9, 1}, 14363c4e0415SDaniel Scheller {0x90700014, 10, 1}, {0x90700014, 11, 1}, 14373c4e0415SDaniel Scheller {0x90700014, 12, 1}, {0x90700014, 13, 1}, 14383c4e0415SDaniel Scheller {0x90700014, 14, 1}, {0x90700014, 15, 1} }; 14393c4e0415SDaniel Scheller struct MXL_REG_FIELD_T xpt_continuous_clock[MXL_HYDRA_DEMOD_MAX] = { 14403c4e0415SDaniel Scheller {0x907001D4, 0, 1}, {0x907001D4, 1, 1}, 14413c4e0415SDaniel Scheller {0x907001D4, 2, 1}, {0x907001D4, 3, 1}, 14423c4e0415SDaniel Scheller {0x907001D4, 4, 1}, {0x907001D4, 5, 1}, 14433c4e0415SDaniel Scheller {0x907001D4, 6, 1}, {0x907001D4, 7, 1} }; 14443c4e0415SDaniel Scheller struct MXL_REG_FIELD_T xpt_nco_clock_rate[MXL_HYDRA_DEMOD_MAX] = { 14453c4e0415SDaniel Scheller {0x90700044, 16, 80}, {0x90700044, 16, 81}, 14463c4e0415SDaniel Scheller {0x90700044, 16, 82}, {0x90700044, 16, 83}, 14473c4e0415SDaniel Scheller {0x90700044, 16, 84}, {0x90700044, 16, 85}, 14483c4e0415SDaniel Scheller {0x90700044, 16, 86}, {0x90700044, 16, 87} }; 14493c4e0415SDaniel Scheller 14503c4e0415SDaniel Scheller demod_id = state->base->ts_map[demod_id]; 14513c4e0415SDaniel Scheller 14523c4e0415SDaniel Scheller if (mpeg_out_param_ptr->enable == MXL_ENABLE) { 14533c4e0415SDaniel Scheller if (mpeg_out_param_ptr->mpeg_mode == 14543c4e0415SDaniel Scheller MXL_HYDRA_MPEG_MODE_PARALLEL) { 14553c4e0415SDaniel Scheller } else { 14563c4e0415SDaniel Scheller cfg_ts_pad_mux(state, MXL_TRUE); 14573c4e0415SDaniel Scheller update_by_mnemonic(state, 14583c4e0415SDaniel Scheller 0x90700010, 27, 1, MXL_FALSE); 14593c4e0415SDaniel Scheller } 14603c4e0415SDaniel Scheller } 14613c4e0415SDaniel Scheller 14623c4e0415SDaniel Scheller nco_count_min = 14633c4e0415SDaniel Scheller (u32)(MXL_HYDRA_NCO_CLK / mpeg_out_param_ptr->max_mpeg_clk_rate); 14643c4e0415SDaniel Scheller 14653c4e0415SDaniel Scheller if (state->base->chipversion >= 2) { 14663c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 14673c4e0415SDaniel Scheller xpt_nco_clock_rate[demod_id].reg_addr, /* Reg Addr */ 14683c4e0415SDaniel Scheller xpt_nco_clock_rate[demod_id].lsb_pos, /* LSB pos */ 14693c4e0415SDaniel Scheller xpt_nco_clock_rate[demod_id].num_of_bits, /* Num of bits */ 14703c4e0415SDaniel Scheller nco_count_min); /* Data */ 14713c4e0415SDaniel Scheller } else 14723c4e0415SDaniel Scheller update_by_mnemonic(state, 0x90700044, 16, 8, nco_count_min); 14733c4e0415SDaniel Scheller 14743c4e0415SDaniel Scheller if (mpeg_out_param_ptr->mpeg_clk_type == MXL_HYDRA_MPEG_CLK_CONTINUOUS) 14753c4e0415SDaniel Scheller clk_type = 1; 14763c4e0415SDaniel Scheller 14773c4e0415SDaniel Scheller if (mpeg_out_param_ptr->mpeg_mode < MXL_HYDRA_MPEG_MODE_PARALLEL) { 14783c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 14793c4e0415SDaniel Scheller xpt_continuous_clock[demod_id].reg_addr, 14803c4e0415SDaniel Scheller xpt_continuous_clock[demod_id].lsb_pos, 14813c4e0415SDaniel Scheller xpt_continuous_clock[demod_id].num_of_bits, 14823c4e0415SDaniel Scheller clk_type); 14833c4e0415SDaniel Scheller } else 14843c4e0415SDaniel Scheller update_by_mnemonic(state, 0x907001D4, 8, 1, clk_type); 14853c4e0415SDaniel Scheller 14863c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 14873c4e0415SDaniel Scheller xpt_sync_polarity[demod_id].reg_addr, 14883c4e0415SDaniel Scheller xpt_sync_polarity[demod_id].lsb_pos, 14893c4e0415SDaniel Scheller xpt_sync_polarity[demod_id].num_of_bits, 14903c4e0415SDaniel Scheller mpeg_out_param_ptr->mpeg_sync_pol); 14913c4e0415SDaniel Scheller 14923c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 14933c4e0415SDaniel Scheller xpt_valid_polarity[demod_id].reg_addr, 14943c4e0415SDaniel Scheller xpt_valid_polarity[demod_id].lsb_pos, 14953c4e0415SDaniel Scheller xpt_valid_polarity[demod_id].num_of_bits, 14963c4e0415SDaniel Scheller mpeg_out_param_ptr->mpeg_valid_pol); 14973c4e0415SDaniel Scheller 14983c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 14993c4e0415SDaniel Scheller xpt_clock_polarity[demod_id].reg_addr, 15003c4e0415SDaniel Scheller xpt_clock_polarity[demod_id].lsb_pos, 15013c4e0415SDaniel Scheller xpt_clock_polarity[demod_id].num_of_bits, 15023c4e0415SDaniel Scheller mpeg_out_param_ptr->mpeg_clk_pol); 15033c4e0415SDaniel Scheller 15043c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 15053c4e0415SDaniel Scheller xpt_sync_byte[demod_id].reg_addr, 15063c4e0415SDaniel Scheller xpt_sync_byte[demod_id].lsb_pos, 15073c4e0415SDaniel Scheller xpt_sync_byte[demod_id].num_of_bits, 15083c4e0415SDaniel Scheller mpeg_out_param_ptr->mpeg_sync_pulse_width); 15093c4e0415SDaniel Scheller 15103c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 15113c4e0415SDaniel Scheller xpt_ts_clock_phase[demod_id].reg_addr, 15123c4e0415SDaniel Scheller xpt_ts_clock_phase[demod_id].lsb_pos, 15133c4e0415SDaniel Scheller xpt_ts_clock_phase[demod_id].num_of_bits, 15143c4e0415SDaniel Scheller mpeg_out_param_ptr->mpeg_clk_phase); 15153c4e0415SDaniel Scheller 15163c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 15173c4e0415SDaniel Scheller xpt_lsb_first[demod_id].reg_addr, 15183c4e0415SDaniel Scheller xpt_lsb_first[demod_id].lsb_pos, 15193c4e0415SDaniel Scheller xpt_lsb_first[demod_id].num_of_bits, 15203c4e0415SDaniel Scheller mpeg_out_param_ptr->lsb_or_msb_first); 15213c4e0415SDaniel Scheller 15223c4e0415SDaniel Scheller switch (mpeg_out_param_ptr->mpeg_error_indication) { 15233c4e0415SDaniel Scheller case MXL_HYDRA_MPEG_ERR_REPLACE_SYNC: 15243c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 15253c4e0415SDaniel Scheller xpt_err_replace_sync[demod_id].reg_addr, 15263c4e0415SDaniel Scheller xpt_err_replace_sync[demod_id].lsb_pos, 15273c4e0415SDaniel Scheller xpt_err_replace_sync[demod_id].num_of_bits, 15283c4e0415SDaniel Scheller MXL_TRUE); 15293c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 15303c4e0415SDaniel Scheller xpt_err_replace_valid[demod_id].reg_addr, 15313c4e0415SDaniel Scheller xpt_err_replace_valid[demod_id].lsb_pos, 15323c4e0415SDaniel Scheller xpt_err_replace_valid[demod_id].num_of_bits, 15333c4e0415SDaniel Scheller MXL_FALSE); 15343c4e0415SDaniel Scheller break; 15353c4e0415SDaniel Scheller 15363c4e0415SDaniel Scheller case MXL_HYDRA_MPEG_ERR_REPLACE_VALID: 15373c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 15383c4e0415SDaniel Scheller xpt_err_replace_sync[demod_id].reg_addr, 15393c4e0415SDaniel Scheller xpt_err_replace_sync[demod_id].lsb_pos, 15403c4e0415SDaniel Scheller xpt_err_replace_sync[demod_id].num_of_bits, 15413c4e0415SDaniel Scheller MXL_FALSE); 15423c4e0415SDaniel Scheller 15433c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 15443c4e0415SDaniel Scheller xpt_err_replace_valid[demod_id].reg_addr, 15453c4e0415SDaniel Scheller xpt_err_replace_valid[demod_id].lsb_pos, 15463c4e0415SDaniel Scheller xpt_err_replace_valid[demod_id].num_of_bits, 15473c4e0415SDaniel Scheller MXL_TRUE); 15483c4e0415SDaniel Scheller break; 15493c4e0415SDaniel Scheller 15503c4e0415SDaniel Scheller case MXL_HYDRA_MPEG_ERR_INDICATION_DISABLED: 15513c4e0415SDaniel Scheller default: 15523c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 15533c4e0415SDaniel Scheller xpt_err_replace_sync[demod_id].reg_addr, 15543c4e0415SDaniel Scheller xpt_err_replace_sync[demod_id].lsb_pos, 15553c4e0415SDaniel Scheller xpt_err_replace_sync[demod_id].num_of_bits, 15563c4e0415SDaniel Scheller MXL_FALSE); 15573c4e0415SDaniel Scheller 15583c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 15593c4e0415SDaniel Scheller xpt_err_replace_valid[demod_id].reg_addr, 15603c4e0415SDaniel Scheller xpt_err_replace_valid[demod_id].lsb_pos, 15613c4e0415SDaniel Scheller xpt_err_replace_valid[demod_id].num_of_bits, 15623c4e0415SDaniel Scheller MXL_FALSE); 15633c4e0415SDaniel Scheller 15643c4e0415SDaniel Scheller break; 15653c4e0415SDaniel Scheller 15663c4e0415SDaniel Scheller } 15673c4e0415SDaniel Scheller 15683c4e0415SDaniel Scheller if (mpeg_out_param_ptr->mpeg_mode != MXL_HYDRA_MPEG_MODE_PARALLEL) { 15693c4e0415SDaniel Scheller status |= update_by_mnemonic(state, 15703c4e0415SDaniel Scheller xpt_enable_output[demod_id].reg_addr, 15713c4e0415SDaniel Scheller xpt_enable_output[demod_id].lsb_pos, 15723c4e0415SDaniel Scheller xpt_enable_output[demod_id].num_of_bits, 15733c4e0415SDaniel Scheller mpeg_out_param_ptr->enable); 15743c4e0415SDaniel Scheller } 15753c4e0415SDaniel Scheller return status; 15763c4e0415SDaniel Scheller } 15773c4e0415SDaniel Scheller 15783c4e0415SDaniel Scheller static int config_mux(struct mxl *state) 15793c4e0415SDaniel Scheller { 15803c4e0415SDaniel Scheller update_by_mnemonic(state, 0x9070000C, 0, 1, 0); 15813c4e0415SDaniel Scheller update_by_mnemonic(state, 0x9070000C, 1, 1, 0); 15823c4e0415SDaniel Scheller update_by_mnemonic(state, 0x9070000C, 2, 1, 0); 15833c4e0415SDaniel Scheller update_by_mnemonic(state, 0x9070000C, 3, 1, 0); 15843c4e0415SDaniel Scheller update_by_mnemonic(state, 0x9070000C, 4, 1, 0); 15853c4e0415SDaniel Scheller update_by_mnemonic(state, 0x9070000C, 5, 1, 0); 15863c4e0415SDaniel Scheller update_by_mnemonic(state, 0x9070000C, 6, 1, 0); 15873c4e0415SDaniel Scheller update_by_mnemonic(state, 0x9070000C, 7, 1, 0); 15883c4e0415SDaniel Scheller update_by_mnemonic(state, 0x90700008, 0, 2, 1); 15893c4e0415SDaniel Scheller update_by_mnemonic(state, 0x90700008, 2, 2, 1); 15903c4e0415SDaniel Scheller return 0; 15913c4e0415SDaniel Scheller } 15923c4e0415SDaniel Scheller 15933c4e0415SDaniel Scheller static int load_fw(struct mxl *state, struct mxl5xx_cfg *cfg) 15943c4e0415SDaniel Scheller { 15953c4e0415SDaniel Scheller int stat = 0; 15963c4e0415SDaniel Scheller u8 *buf; 15973c4e0415SDaniel Scheller 15983c4e0415SDaniel Scheller if (cfg->fw) 15993c4e0415SDaniel Scheller return firmware_download(state, cfg->fw, cfg->fw_len); 16003c4e0415SDaniel Scheller 16013c4e0415SDaniel Scheller if (!cfg->fw_read) 16023c4e0415SDaniel Scheller return -1; 16033c4e0415SDaniel Scheller 16043c4e0415SDaniel Scheller buf = vmalloc(0x40000); 16053c4e0415SDaniel Scheller if (!buf) 16063c4e0415SDaniel Scheller return -ENOMEM; 16073c4e0415SDaniel Scheller 16083c4e0415SDaniel Scheller cfg->fw_read(cfg->fw_priv, buf, 0x40000); 16093c4e0415SDaniel Scheller stat = firmware_download(state, buf, 0x40000); 16103c4e0415SDaniel Scheller vfree(buf); 16113c4e0415SDaniel Scheller 16123c4e0415SDaniel Scheller return stat; 16133c4e0415SDaniel Scheller } 16143c4e0415SDaniel Scheller 16153c4e0415SDaniel Scheller static int validate_sku(struct mxl *state) 16163c4e0415SDaniel Scheller { 16173c4e0415SDaniel Scheller u32 pad_mux_bond = 0, prcm_chip_id = 0, prcm_so_cid = 0; 16183c4e0415SDaniel Scheller int status; 16193c4e0415SDaniel Scheller u32 type = state->base->type; 16203c4e0415SDaniel Scheller 16213c4e0415SDaniel Scheller status = read_by_mnemonic(state, 0x90000190, 0, 3, &pad_mux_bond); 16223c4e0415SDaniel Scheller status |= read_by_mnemonic(state, 0x80030000, 0, 12, &prcm_chip_id); 16233c4e0415SDaniel Scheller status |= read_by_mnemonic(state, 0x80030004, 24, 8, &prcm_so_cid); 16243c4e0415SDaniel Scheller if (status) 16253c4e0415SDaniel Scheller return -1; 16263c4e0415SDaniel Scheller 16273c4e0415SDaniel Scheller dev_info(state->i2cdev, "padMuxBond=%08x, prcmChipId=%08x, prcmSoCId=%08x\n", 16283c4e0415SDaniel Scheller pad_mux_bond, prcm_chip_id, prcm_so_cid); 16293c4e0415SDaniel Scheller 16303c4e0415SDaniel Scheller if (prcm_chip_id != 0x560) { 16313c4e0415SDaniel Scheller switch (pad_mux_bond) { 16323c4e0415SDaniel Scheller case MXL_HYDRA_SKU_ID_581: 16333c4e0415SDaniel Scheller if (type == MXL_HYDRA_DEVICE_581) 16343c4e0415SDaniel Scheller return 0; 16353c4e0415SDaniel Scheller if (type == MXL_HYDRA_DEVICE_581S) { 16363c4e0415SDaniel Scheller state->base->type = MXL_HYDRA_DEVICE_581; 16373c4e0415SDaniel Scheller return 0; 16383c4e0415SDaniel Scheller } 16393c4e0415SDaniel Scheller break; 16403c4e0415SDaniel Scheller case MXL_HYDRA_SKU_ID_584: 16413c4e0415SDaniel Scheller if (type == MXL_HYDRA_DEVICE_584) 16423c4e0415SDaniel Scheller return 0; 16433c4e0415SDaniel Scheller break; 16443c4e0415SDaniel Scheller case MXL_HYDRA_SKU_ID_544: 16453c4e0415SDaniel Scheller if (type == MXL_HYDRA_DEVICE_544) 16463c4e0415SDaniel Scheller return 0; 16473c4e0415SDaniel Scheller if (type == MXL_HYDRA_DEVICE_542) 16483c4e0415SDaniel Scheller return 0; 16493c4e0415SDaniel Scheller break; 16503c4e0415SDaniel Scheller case MXL_HYDRA_SKU_ID_582: 16513c4e0415SDaniel Scheller if (type == MXL_HYDRA_DEVICE_582) 16523c4e0415SDaniel Scheller return 0; 16533c4e0415SDaniel Scheller break; 16543c4e0415SDaniel Scheller default: 16553c4e0415SDaniel Scheller return -1; 16563c4e0415SDaniel Scheller } 16573c4e0415SDaniel Scheller } else { 16583c4e0415SDaniel Scheller 16593c4e0415SDaniel Scheller } 16603c4e0415SDaniel Scheller return -1; 16613c4e0415SDaniel Scheller } 16623c4e0415SDaniel Scheller 16633c4e0415SDaniel Scheller static int get_fwinfo(struct mxl *state) 16643c4e0415SDaniel Scheller { 16653c4e0415SDaniel Scheller int status; 16663c4e0415SDaniel Scheller u32 val = 0; 16673c4e0415SDaniel Scheller 16683c4e0415SDaniel Scheller status = read_by_mnemonic(state, 0x90000190, 0, 3, &val); 16693c4e0415SDaniel Scheller if (status) 16703c4e0415SDaniel Scheller return status; 16713c4e0415SDaniel Scheller dev_info(state->i2cdev, "chipID=%08x\n", val); 16723c4e0415SDaniel Scheller 16733c4e0415SDaniel Scheller status = read_by_mnemonic(state, 0x80030004, 8, 8, &val); 16743c4e0415SDaniel Scheller if (status) 16753c4e0415SDaniel Scheller return status; 16763c4e0415SDaniel Scheller dev_info(state->i2cdev, "chipVer=%08x\n", val); 16773c4e0415SDaniel Scheller 16783c4e0415SDaniel Scheller status = read_register(state, HYDRA_FIRMWARE_VERSION, &val); 16793c4e0415SDaniel Scheller if (status) 16803c4e0415SDaniel Scheller return status; 16813c4e0415SDaniel Scheller dev_info(state->i2cdev, "FWVer=%08x\n", val); 16823c4e0415SDaniel Scheller 16833c4e0415SDaniel Scheller state->base->fwversion = val; 16843c4e0415SDaniel Scheller return status; 16853c4e0415SDaniel Scheller } 16863c4e0415SDaniel Scheller 16873c4e0415SDaniel Scheller 16883c4e0415SDaniel Scheller static u8 ts_map1_to_1[MXL_HYDRA_DEMOD_MAX] = { 16893c4e0415SDaniel Scheller MXL_HYDRA_DEMOD_ID_0, 16903c4e0415SDaniel Scheller MXL_HYDRA_DEMOD_ID_1, 16913c4e0415SDaniel Scheller MXL_HYDRA_DEMOD_ID_2, 16923c4e0415SDaniel Scheller MXL_HYDRA_DEMOD_ID_3, 16933c4e0415SDaniel Scheller MXL_HYDRA_DEMOD_ID_4, 16943c4e0415SDaniel Scheller MXL_HYDRA_DEMOD_ID_5, 16953c4e0415SDaniel Scheller MXL_HYDRA_DEMOD_ID_6, 16963c4e0415SDaniel Scheller MXL_HYDRA_DEMOD_ID_7, 16973c4e0415SDaniel Scheller }; 16983c4e0415SDaniel Scheller 16993c4e0415SDaniel Scheller static u8 ts_map54x[MXL_HYDRA_DEMOD_MAX] = { 17003c4e0415SDaniel Scheller MXL_HYDRA_DEMOD_ID_2, 17013c4e0415SDaniel Scheller MXL_HYDRA_DEMOD_ID_3, 17023c4e0415SDaniel Scheller MXL_HYDRA_DEMOD_ID_4, 17033c4e0415SDaniel Scheller MXL_HYDRA_DEMOD_ID_5, 17043c4e0415SDaniel Scheller MXL_HYDRA_DEMOD_MAX, 17053c4e0415SDaniel Scheller MXL_HYDRA_DEMOD_MAX, 17063c4e0415SDaniel Scheller MXL_HYDRA_DEMOD_MAX, 17073c4e0415SDaniel Scheller MXL_HYDRA_DEMOD_MAX, 17083c4e0415SDaniel Scheller }; 17093c4e0415SDaniel Scheller 17103c4e0415SDaniel Scheller static int probe(struct mxl *state, struct mxl5xx_cfg *cfg) 17113c4e0415SDaniel Scheller { 17123c4e0415SDaniel Scheller u32 chipver; 17133c4e0415SDaniel Scheller int fw, status, j; 17143c4e0415SDaniel Scheller struct MXL_HYDRA_MPEGOUT_PARAM_T mpeg_interface_cfg; 17153c4e0415SDaniel Scheller 17163c4e0415SDaniel Scheller state->base->ts_map = ts_map1_to_1; 17173c4e0415SDaniel Scheller 17183c4e0415SDaniel Scheller switch (state->base->type) { 17193c4e0415SDaniel Scheller case MXL_HYDRA_DEVICE_581: 17203c4e0415SDaniel Scheller case MXL_HYDRA_DEVICE_581S: 17213c4e0415SDaniel Scheller state->base->can_clkout = 1; 17223c4e0415SDaniel Scheller state->base->demod_num = 8; 17233c4e0415SDaniel Scheller state->base->tuner_num = 1; 17243c4e0415SDaniel Scheller state->base->sku_type = MXL_HYDRA_SKU_TYPE_581; 17253c4e0415SDaniel Scheller break; 17263c4e0415SDaniel Scheller case MXL_HYDRA_DEVICE_582: 17273c4e0415SDaniel Scheller state->base->can_clkout = 1; 17283c4e0415SDaniel Scheller state->base->demod_num = 8; 17293c4e0415SDaniel Scheller state->base->tuner_num = 3; 17303c4e0415SDaniel Scheller state->base->sku_type = MXL_HYDRA_SKU_TYPE_582; 17313c4e0415SDaniel Scheller break; 17323c4e0415SDaniel Scheller case MXL_HYDRA_DEVICE_585: 17333c4e0415SDaniel Scheller state->base->can_clkout = 0; 17343c4e0415SDaniel Scheller state->base->demod_num = 8; 17353c4e0415SDaniel Scheller state->base->tuner_num = 4; 17363c4e0415SDaniel Scheller state->base->sku_type = MXL_HYDRA_SKU_TYPE_585; 17373c4e0415SDaniel Scheller break; 17383c4e0415SDaniel Scheller case MXL_HYDRA_DEVICE_544: 17393c4e0415SDaniel Scheller state->base->can_clkout = 0; 17403c4e0415SDaniel Scheller state->base->demod_num = 4; 17413c4e0415SDaniel Scheller state->base->tuner_num = 4; 17423c4e0415SDaniel Scheller state->base->sku_type = MXL_HYDRA_SKU_TYPE_544; 17433c4e0415SDaniel Scheller state->base->ts_map = ts_map54x; 17443c4e0415SDaniel Scheller break; 17453c4e0415SDaniel Scheller case MXL_HYDRA_DEVICE_541: 17463c4e0415SDaniel Scheller case MXL_HYDRA_DEVICE_541S: 17473c4e0415SDaniel Scheller state->base->can_clkout = 0; 17483c4e0415SDaniel Scheller state->base->demod_num = 4; 17493c4e0415SDaniel Scheller state->base->tuner_num = 1; 17503c4e0415SDaniel Scheller state->base->sku_type = MXL_HYDRA_SKU_TYPE_541; 17513c4e0415SDaniel Scheller state->base->ts_map = ts_map54x; 17523c4e0415SDaniel Scheller break; 17533c4e0415SDaniel Scheller case MXL_HYDRA_DEVICE_561: 17543c4e0415SDaniel Scheller case MXL_HYDRA_DEVICE_561S: 17553c4e0415SDaniel Scheller state->base->can_clkout = 0; 17563c4e0415SDaniel Scheller state->base->demod_num = 6; 17573c4e0415SDaniel Scheller state->base->tuner_num = 1; 17583c4e0415SDaniel Scheller state->base->sku_type = MXL_HYDRA_SKU_TYPE_561; 17593c4e0415SDaniel Scheller break; 17603c4e0415SDaniel Scheller case MXL_HYDRA_DEVICE_568: 17613c4e0415SDaniel Scheller state->base->can_clkout = 0; 17623c4e0415SDaniel Scheller state->base->demod_num = 8; 17633c4e0415SDaniel Scheller state->base->tuner_num = 1; 17643c4e0415SDaniel Scheller state->base->chan_bond = 1; 17653c4e0415SDaniel Scheller state->base->sku_type = MXL_HYDRA_SKU_TYPE_568; 17663c4e0415SDaniel Scheller break; 17673c4e0415SDaniel Scheller case MXL_HYDRA_DEVICE_542: 17683c4e0415SDaniel Scheller state->base->can_clkout = 1; 17693c4e0415SDaniel Scheller state->base->demod_num = 4; 17703c4e0415SDaniel Scheller state->base->tuner_num = 3; 17713c4e0415SDaniel Scheller state->base->sku_type = MXL_HYDRA_SKU_TYPE_542; 17723c4e0415SDaniel Scheller state->base->ts_map = ts_map54x; 17733c4e0415SDaniel Scheller break; 17743c4e0415SDaniel Scheller case MXL_HYDRA_DEVICE_TEST: 17753c4e0415SDaniel Scheller case MXL_HYDRA_DEVICE_584: 17763c4e0415SDaniel Scheller default: 17773c4e0415SDaniel Scheller state->base->can_clkout = 0; 17783c4e0415SDaniel Scheller state->base->demod_num = 8; 17793c4e0415SDaniel Scheller state->base->tuner_num = 4; 17803c4e0415SDaniel Scheller state->base->sku_type = MXL_HYDRA_SKU_TYPE_584; 17813c4e0415SDaniel Scheller break; 17823c4e0415SDaniel Scheller } 17833c4e0415SDaniel Scheller 17843c4e0415SDaniel Scheller status = validate_sku(state); 17853c4e0415SDaniel Scheller if (status) 17863c4e0415SDaniel Scheller return status; 17873c4e0415SDaniel Scheller 17883c4e0415SDaniel Scheller update_by_mnemonic(state, 0x80030014, 9, 1, 1); 17893c4e0415SDaniel Scheller update_by_mnemonic(state, 0x8003003C, 12, 1, 1); 17903c4e0415SDaniel Scheller status = read_by_mnemonic(state, 0x80030000, 12, 4, &chipver); 17913c4e0415SDaniel Scheller if (status) 17923c4e0415SDaniel Scheller state->base->chipversion = 0; 17933c4e0415SDaniel Scheller else 17943c4e0415SDaniel Scheller state->base->chipversion = (chipver == 2) ? 2 : 1; 17953c4e0415SDaniel Scheller dev_info(state->i2cdev, "Hydra chip version %u\n", 17963c4e0415SDaniel Scheller state->base->chipversion); 17973c4e0415SDaniel Scheller 17983c4e0415SDaniel Scheller cfg_dev_xtal(state, cfg->clk, cfg->cap, 0); 17993c4e0415SDaniel Scheller 18003c4e0415SDaniel Scheller fw = firmware_is_alive(state); 18013c4e0415SDaniel Scheller if (!fw) { 18023c4e0415SDaniel Scheller status = load_fw(state, cfg); 18033c4e0415SDaniel Scheller if (status) 18043c4e0415SDaniel Scheller return status; 18053c4e0415SDaniel Scheller } 18063c4e0415SDaniel Scheller get_fwinfo(state); 18073c4e0415SDaniel Scheller 18083c4e0415SDaniel Scheller config_mux(state); 18093c4e0415SDaniel Scheller mpeg_interface_cfg.enable = MXL_ENABLE; 18103c4e0415SDaniel Scheller mpeg_interface_cfg.lsb_or_msb_first = MXL_HYDRA_MPEG_SERIAL_MSB_1ST; 18113c4e0415SDaniel Scheller /* supports only (0-104&139)MHz */ 18123c4e0415SDaniel Scheller if (cfg->ts_clk) 18133c4e0415SDaniel Scheller mpeg_interface_cfg.max_mpeg_clk_rate = cfg->ts_clk; 18143c4e0415SDaniel Scheller else 18153c4e0415SDaniel Scheller mpeg_interface_cfg.max_mpeg_clk_rate = 69; /* 139; */ 18163c4e0415SDaniel Scheller mpeg_interface_cfg.mpeg_clk_phase = MXL_HYDRA_MPEG_CLK_PHASE_SHIFT_0_DEG; 18173c4e0415SDaniel Scheller mpeg_interface_cfg.mpeg_clk_pol = MXL_HYDRA_MPEG_CLK_IN_PHASE; 18183c4e0415SDaniel Scheller /* MXL_HYDRA_MPEG_CLK_GAPPED; */ 18193c4e0415SDaniel Scheller mpeg_interface_cfg.mpeg_clk_type = MXL_HYDRA_MPEG_CLK_CONTINUOUS; 18203c4e0415SDaniel Scheller mpeg_interface_cfg.mpeg_error_indication = 18213c4e0415SDaniel Scheller MXL_HYDRA_MPEG_ERR_INDICATION_DISABLED; 18223c4e0415SDaniel Scheller mpeg_interface_cfg.mpeg_mode = MXL_HYDRA_MPEG_MODE_SERIAL_3_WIRE; 18233c4e0415SDaniel Scheller mpeg_interface_cfg.mpeg_sync_pol = MXL_HYDRA_MPEG_ACTIVE_HIGH; 18243c4e0415SDaniel Scheller mpeg_interface_cfg.mpeg_sync_pulse_width = MXL_HYDRA_MPEG_SYNC_WIDTH_BIT; 18253c4e0415SDaniel Scheller mpeg_interface_cfg.mpeg_valid_pol = MXL_HYDRA_MPEG_ACTIVE_HIGH; 18263c4e0415SDaniel Scheller 18273c4e0415SDaniel Scheller for (j = 0; j < state->base->demod_num; j++) { 18283c4e0415SDaniel Scheller status = config_ts(state, (enum MXL_HYDRA_DEMOD_ID_E) j, 18293c4e0415SDaniel Scheller &mpeg_interface_cfg); 18303c4e0415SDaniel Scheller if (status) 18313c4e0415SDaniel Scheller return status; 18323c4e0415SDaniel Scheller } 18333c4e0415SDaniel Scheller set_drive_strength(state, 1); 18343c4e0415SDaniel Scheller return 0; 18353c4e0415SDaniel Scheller } 18363c4e0415SDaniel Scheller 18373c4e0415SDaniel Scheller struct dvb_frontend *mxl5xx_attach(struct i2c_adapter *i2c, 18383c4e0415SDaniel Scheller struct mxl5xx_cfg *cfg, u32 demod, u32 tuner, 18393c4e0415SDaniel Scheller int (**fn_set_input)(struct dvb_frontend *, int)) 18403c4e0415SDaniel Scheller { 18413c4e0415SDaniel Scheller struct mxl *state; 18423c4e0415SDaniel Scheller struct mxl_base *base; 18433c4e0415SDaniel Scheller 18443c4e0415SDaniel Scheller state = kzalloc(sizeof(struct mxl), GFP_KERNEL); 18453c4e0415SDaniel Scheller if (!state) 18463c4e0415SDaniel Scheller return NULL; 18473c4e0415SDaniel Scheller 18483c4e0415SDaniel Scheller state->demod = demod; 18493c4e0415SDaniel Scheller state->tuner = tuner; 18503c4e0415SDaniel Scheller state->tuner_in_use = 0xffffffff; 18513c4e0415SDaniel Scheller state->i2cdev = &i2c->dev; 18523c4e0415SDaniel Scheller 18533c4e0415SDaniel Scheller base = match_base(i2c, cfg->adr); 18543c4e0415SDaniel Scheller if (base) { 18553c4e0415SDaniel Scheller base->count++; 18563c4e0415SDaniel Scheller if (base->count > base->demod_num) 18573c4e0415SDaniel Scheller goto fail; 18583c4e0415SDaniel Scheller state->base = base; 18593c4e0415SDaniel Scheller } else { 18603c4e0415SDaniel Scheller base = kzalloc(sizeof(struct mxl_base), GFP_KERNEL); 18613c4e0415SDaniel Scheller if (!base) 18623c4e0415SDaniel Scheller goto fail; 18633c4e0415SDaniel Scheller base->i2c = i2c; 18643c4e0415SDaniel Scheller base->adr = cfg->adr; 18653c4e0415SDaniel Scheller base->type = cfg->type; 18663c4e0415SDaniel Scheller base->count = 1; 18673c4e0415SDaniel Scheller mutex_init(&base->i2c_lock); 18683c4e0415SDaniel Scheller mutex_init(&base->status_lock); 18693c4e0415SDaniel Scheller mutex_init(&base->tune_lock); 18703c4e0415SDaniel Scheller INIT_LIST_HEAD(&base->mxls); 18713c4e0415SDaniel Scheller 18723c4e0415SDaniel Scheller state->base = base; 18733c4e0415SDaniel Scheller if (probe(state, cfg) < 0) { 18743c4e0415SDaniel Scheller kfree(base); 18753c4e0415SDaniel Scheller goto fail; 18763c4e0415SDaniel Scheller } 18773c4e0415SDaniel Scheller list_add(&base->mxllist, &mxllist); 18783c4e0415SDaniel Scheller } 18793c4e0415SDaniel Scheller state->fe.ops = mxl_ops; 18803c4e0415SDaniel Scheller state->xbar[0] = 4; 18813c4e0415SDaniel Scheller state->xbar[1] = demod; 18823c4e0415SDaniel Scheller state->xbar[2] = 8; 18833c4e0415SDaniel Scheller state->fe.demodulator_priv = state; 18843c4e0415SDaniel Scheller *fn_set_input = set_input; 18853c4e0415SDaniel Scheller 18863c4e0415SDaniel Scheller list_add(&state->mxl, &base->mxls); 18873c4e0415SDaniel Scheller return &state->fe; 18883c4e0415SDaniel Scheller 18893c4e0415SDaniel Scheller fail: 18903c4e0415SDaniel Scheller kfree(state); 18913c4e0415SDaniel Scheller return NULL; 18923c4e0415SDaniel Scheller } 18933c4e0415SDaniel Scheller EXPORT_SYMBOL_GPL(mxl5xx_attach); 18943c4e0415SDaniel Scheller 18953c4e0415SDaniel Scheller MODULE_DESCRIPTION("MaxLinear MxL5xx DVB-S/S2 tuner-demodulator driver"); 18963c4e0415SDaniel Scheller MODULE_AUTHOR("Ralph and Marcus Metzler, Metzler Brothers Systementwicklung GbR"); 1897229b6ea6SDaniel Scheller MODULE_LICENSE("GPL v2"); 1898