xref: /openbmc/linux/drivers/media/dvb-frontends/mxl5xx.c (revision 28fc5a367ef0d856a5f3f49a73a391a51b035fdb)
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 			     &reg_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 *) &reg[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 *) &reg[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 			     &reg_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 			     &reg_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 *) &reg_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, &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