xref: /openbmc/linux/drivers/media/dvb-frontends/mxl5xx.c (revision f71c43060aa534df9ae2a055be983bd7194c4a13)
13c4e0415SDaniel Scheller /*
23c4e0415SDaniel Scheller  * Driver for the MaxLinear MxL5xx family of tuners/demods
33c4e0415SDaniel Scheller  *
43c4e0415SDaniel Scheller  * Copyright (C) 2014-2015 Ralph Metzler <rjkm@metzlerbros.de>
53c4e0415SDaniel Scheller  *                         Marcus Metzler <mocm@metzlerbros.de>
63c4e0415SDaniel Scheller  *                         developed for Digital Devices GmbH
73c4e0415SDaniel Scheller  *
83c4e0415SDaniel Scheller  * based on code:
93c4e0415SDaniel Scheller  * Copyright (c) 2011-2013 MaxLinear, Inc. All rights reserved
103c4e0415SDaniel Scheller  * which was released under GPL V2
113c4e0415SDaniel Scheller  *
123c4e0415SDaniel Scheller  * This program is free software; you can redistribute it and/or
133c4e0415SDaniel Scheller  * modify it under the terms of the GNU General Public License
143c4e0415SDaniel Scheller  * version 2, as published by the Free Software Foundation.
153c4e0415SDaniel Scheller  *
163c4e0415SDaniel Scheller  * This program is distributed in the hope that it will be useful,
173c4e0415SDaniel Scheller  * but WITHOUT ANY WARRANTY; without even the implied warranty of
183c4e0415SDaniel Scheller  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
193c4e0415SDaniel Scheller  * GNU General Public License for more details.
203c4e0415SDaniel Scheller  *
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 
363c4e0415SDaniel Scheller #include "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 
46*f71c4306SDaniel 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 
3783c4e0415SDaniel Scheller static int get_algo(struct dvb_frontend *fe)
3793c4e0415SDaniel Scheller {
3803c4e0415SDaniel Scheller 	return DVBFE_ALGO_HW;
3813c4e0415SDaniel Scheller }
3823c4e0415SDaniel Scheller 
3833c4e0415SDaniel Scheller static int cfg_demod_abort_tune(struct mxl *state)
3843c4e0415SDaniel Scheller {
3853c4e0415SDaniel Scheller 	struct MXL_HYDRA_DEMOD_ABORT_TUNE_T abort_tune_cmd;
3863c4e0415SDaniel Scheller 	u8 cmd_size = sizeof(abort_tune_cmd);
3873c4e0415SDaniel Scheller 	u8 cmd_buff[MXL_HYDRA_OEM_MAX_CMD_BUFF_LEN];
3883c4e0415SDaniel Scheller 
3893c4e0415SDaniel Scheller 	abort_tune_cmd.demod_id = state->demod;
3903c4e0415SDaniel Scheller 	BUILD_HYDRA_CMD(MXL_HYDRA_ABORT_TUNE_CMD, MXL_CMD_WRITE,
3913c4e0415SDaniel Scheller 			cmd_size, &abort_tune_cmd, cmd_buff);
3923c4e0415SDaniel Scheller 	return send_command(state, cmd_size + MXL_HYDRA_CMD_HEADER_SIZE,
3933c4e0415SDaniel Scheller 			    &cmd_buff[0]);
3943c4e0415SDaniel Scheller }
3953c4e0415SDaniel Scheller 
3963c4e0415SDaniel Scheller static int send_master_cmd(struct dvb_frontend *fe,
3973c4e0415SDaniel Scheller 			   struct dvb_diseqc_master_cmd *cmd)
3983c4e0415SDaniel Scheller {
3993c4e0415SDaniel Scheller 	/*struct mxl *state = fe->demodulator_priv;*/
4003c4e0415SDaniel Scheller 
4013c4e0415SDaniel Scheller 	return 0; /*CfgDemodAbortTune(state);*/
4023c4e0415SDaniel Scheller }
4033c4e0415SDaniel Scheller 
4043c4e0415SDaniel Scheller static int set_parameters(struct dvb_frontend *fe)
4053c4e0415SDaniel Scheller {
4063c4e0415SDaniel Scheller 	struct mxl *state = fe->demodulator_priv;
4073c4e0415SDaniel Scheller 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
4083c4e0415SDaniel Scheller 	struct MXL_HYDRA_DEMOD_PARAM_T demod_chan_cfg;
4093c4e0415SDaniel Scheller 	u8 cmd_size = sizeof(demod_chan_cfg);
4103c4e0415SDaniel Scheller 	u8 cmd_buff[MXL_HYDRA_OEM_MAX_CMD_BUFF_LEN];
4113c4e0415SDaniel Scheller 	u32 srange = 10;
4123c4e0415SDaniel Scheller 	int stat;
4133c4e0415SDaniel Scheller 
4143c4e0415SDaniel Scheller 	if (p->frequency < 950000 || p->frequency > 2150000)
4153c4e0415SDaniel Scheller 		return -EINVAL;
4163c4e0415SDaniel Scheller 	if (p->symbol_rate < 1000000 || p->symbol_rate > 45000000)
4173c4e0415SDaniel Scheller 		return -EINVAL;
4183c4e0415SDaniel Scheller 
4193c4e0415SDaniel Scheller 	/* CfgDemodAbortTune(state); */
4203c4e0415SDaniel Scheller 
4213c4e0415SDaniel Scheller 	switch (p->delivery_system) {
4223c4e0415SDaniel Scheller 	case SYS_DSS:
4233c4e0415SDaniel Scheller 		demod_chan_cfg.standard = MXL_HYDRA_DSS;
4243c4e0415SDaniel Scheller 		demod_chan_cfg.roll_off = MXL_HYDRA_ROLLOFF_AUTO;
4253c4e0415SDaniel Scheller 		break;
4263c4e0415SDaniel Scheller 	case SYS_DVBS:
4273c4e0415SDaniel Scheller 		srange = p->symbol_rate / 1000000;
4283c4e0415SDaniel Scheller 		if (srange > 10)
4293c4e0415SDaniel Scheller 			srange = 10;
4303c4e0415SDaniel Scheller 		demod_chan_cfg.standard = MXL_HYDRA_DVBS;
4313c4e0415SDaniel Scheller 		demod_chan_cfg.roll_off = MXL_HYDRA_ROLLOFF_0_35;
4323c4e0415SDaniel Scheller 		demod_chan_cfg.modulation_scheme = MXL_HYDRA_MOD_QPSK;
4333c4e0415SDaniel Scheller 		demod_chan_cfg.pilots = MXL_HYDRA_PILOTS_OFF;
4343c4e0415SDaniel Scheller 		break;
4353c4e0415SDaniel Scheller 	case SYS_DVBS2:
4363c4e0415SDaniel Scheller 		demod_chan_cfg.standard = MXL_HYDRA_DVBS2;
4373c4e0415SDaniel Scheller 		demod_chan_cfg.roll_off = MXL_HYDRA_ROLLOFF_AUTO;
4383c4e0415SDaniel Scheller 		demod_chan_cfg.modulation_scheme = MXL_HYDRA_MOD_AUTO;
4393c4e0415SDaniel Scheller 		demod_chan_cfg.pilots = MXL_HYDRA_PILOTS_AUTO;
4403c4e0415SDaniel Scheller 		/* cfg_scrambler(state); */
4413c4e0415SDaniel Scheller 		break;
4423c4e0415SDaniel Scheller 	default:
4433c4e0415SDaniel Scheller 		return -EINVAL;
4443c4e0415SDaniel Scheller 	}
4453c4e0415SDaniel Scheller 	demod_chan_cfg.tuner_index = state->tuner;
4463c4e0415SDaniel Scheller 	demod_chan_cfg.demod_index = state->demod;
4473c4e0415SDaniel Scheller 	demod_chan_cfg.frequency_in_hz = p->frequency * 1000;
4483c4e0415SDaniel Scheller 	demod_chan_cfg.symbol_rate_in_hz = p->symbol_rate;
4493c4e0415SDaniel Scheller 	demod_chan_cfg.max_carrier_offset_in_mhz = srange;
4503c4e0415SDaniel Scheller 	demod_chan_cfg.spectrum_inversion = MXL_HYDRA_SPECTRUM_AUTO;
4513c4e0415SDaniel Scheller 	demod_chan_cfg.fec_code_rate = MXL_HYDRA_FEC_AUTO;
4523c4e0415SDaniel Scheller 
4533c4e0415SDaniel Scheller 	mutex_lock(&state->base->tune_lock);
4543c4e0415SDaniel Scheller 	if (time_after(jiffies + msecs_to_jiffies(200),
4553c4e0415SDaniel Scheller 		       state->base->next_tune))
4563c4e0415SDaniel Scheller 		while (time_before(jiffies, state->base->next_tune))
4573c4e0415SDaniel Scheller 			usleep_range(10000, 11000);
4583c4e0415SDaniel Scheller 	state->base->next_tune = jiffies + msecs_to_jiffies(100);
4593c4e0415SDaniel Scheller 	state->tuner_in_use = state->tuner;
4603c4e0415SDaniel Scheller 	BUILD_HYDRA_CMD(MXL_HYDRA_DEMOD_SET_PARAM_CMD, MXL_CMD_WRITE,
4613c4e0415SDaniel Scheller 			cmd_size, &demod_chan_cfg, cmd_buff);
4623c4e0415SDaniel Scheller 	stat = send_command(state, cmd_size + MXL_HYDRA_CMD_HEADER_SIZE,
4633c4e0415SDaniel Scheller 			    &cmd_buff[0]);
4643c4e0415SDaniel Scheller 	mutex_unlock(&state->base->tune_lock);
4653c4e0415SDaniel Scheller 	return stat;
4663c4e0415SDaniel Scheller }
4673c4e0415SDaniel Scheller 
4683c4e0415SDaniel Scheller static int enable_tuner(struct mxl *state, u32 tuner, u32 enable);
4693c4e0415SDaniel Scheller 
4703c4e0415SDaniel Scheller static int sleep(struct dvb_frontend *fe)
4713c4e0415SDaniel Scheller {
4723c4e0415SDaniel Scheller 	struct mxl *state = fe->demodulator_priv;
4733c4e0415SDaniel Scheller 	struct mxl *p;
4743c4e0415SDaniel Scheller 
4753c4e0415SDaniel Scheller 	cfg_demod_abort_tune(state);
4763c4e0415SDaniel Scheller 	if (state->tuner_in_use != 0xffffffff) {
4773c4e0415SDaniel Scheller 		mutex_lock(&state->base->tune_lock);
4783c4e0415SDaniel Scheller 		state->tuner_in_use = 0xffffffff;
4793c4e0415SDaniel Scheller 		list_for_each_entry(p, &state->base->mxls, mxl) {
4803c4e0415SDaniel Scheller 			if (p->tuner_in_use == state->tuner)
4813c4e0415SDaniel Scheller 				break;
4823c4e0415SDaniel Scheller 		}
4833c4e0415SDaniel Scheller 		if (&p->mxl == &state->base->mxls)
4843c4e0415SDaniel Scheller 			enable_tuner(state, state->tuner, 0);
4853c4e0415SDaniel Scheller 		mutex_unlock(&state->base->tune_lock);
4863c4e0415SDaniel Scheller 	}
4873c4e0415SDaniel Scheller 	return 0;
4883c4e0415SDaniel Scheller }
4893c4e0415SDaniel Scheller 
4903c4e0415SDaniel Scheller static int read_snr(struct dvb_frontend *fe)
4913c4e0415SDaniel Scheller {
4923c4e0415SDaniel Scheller 	struct mxl *state = fe->demodulator_priv;
4933c4e0415SDaniel Scheller 	int stat;
4943c4e0415SDaniel Scheller 	u32 reg_data = 0;
4953c4e0415SDaniel Scheller 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
4963c4e0415SDaniel Scheller 
4973c4e0415SDaniel Scheller 	mutex_lock(&state->base->status_lock);
4983c4e0415SDaniel Scheller 	HYDRA_DEMOD_STATUS_LOCK(state, state->demod);
4993c4e0415SDaniel Scheller 	stat = read_register(state, (HYDRA_DMD_SNR_ADDR_OFFSET +
5003c4e0415SDaniel Scheller 				     HYDRA_DMD_STATUS_OFFSET(state->demod)),
5013c4e0415SDaniel Scheller 			     &reg_data);
5023c4e0415SDaniel Scheller 	HYDRA_DEMOD_STATUS_UNLOCK(state, state->demod);
5033c4e0415SDaniel Scheller 	mutex_unlock(&state->base->status_lock);
5043c4e0415SDaniel Scheller 
5053c4e0415SDaniel Scheller 	p->cnr.stat[0].scale = FE_SCALE_DECIBEL;
5063c4e0415SDaniel Scheller 	p->cnr.stat[0].svalue = (s16)reg_data * 10;
5073c4e0415SDaniel Scheller 
5083c4e0415SDaniel Scheller 	return stat;
5093c4e0415SDaniel Scheller }
5103c4e0415SDaniel Scheller 
5113c4e0415SDaniel Scheller static int read_ber(struct dvb_frontend *fe)
5123c4e0415SDaniel Scheller {
5133c4e0415SDaniel Scheller 	struct mxl *state = fe->demodulator_priv;
5143c4e0415SDaniel Scheller 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
5153c4e0415SDaniel Scheller 	u32 reg[8];
5163c4e0415SDaniel Scheller 
5173c4e0415SDaniel Scheller 	mutex_lock(&state->base->status_lock);
5183c4e0415SDaniel Scheller 	HYDRA_DEMOD_STATUS_LOCK(state, state->demod);
5193c4e0415SDaniel Scheller 	read_register_block(state,
5203c4e0415SDaniel Scheller 		(HYDRA_DMD_DVBS_1ST_CORR_RS_ERRORS_ADDR_OFFSET +
5213c4e0415SDaniel Scheller 		 HYDRA_DMD_STATUS_OFFSET(state->demod)),
5223c4e0415SDaniel Scheller 		(4 * sizeof(u32)),
5233c4e0415SDaniel Scheller 		(u8 *) &reg[0]);
5243c4e0415SDaniel Scheller 	HYDRA_DEMOD_STATUS_UNLOCK(state, state->demod);
5253c4e0415SDaniel Scheller 
5263c4e0415SDaniel Scheller 	switch (p->delivery_system) {
5273c4e0415SDaniel Scheller 	case SYS_DSS:
5283c4e0415SDaniel Scheller 	case SYS_DVBS:
5293c4e0415SDaniel Scheller 		p->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER;
5303c4e0415SDaniel Scheller 		p->pre_bit_error.stat[0].uvalue = reg[2];
5313c4e0415SDaniel Scheller 		p->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER;
5323c4e0415SDaniel Scheller 		p->pre_bit_count.stat[0].uvalue = reg[3];
5333c4e0415SDaniel Scheller 		break;
5343c4e0415SDaniel Scheller 	default:
5353c4e0415SDaniel Scheller 		break;
5363c4e0415SDaniel Scheller 	}
5373c4e0415SDaniel Scheller 
5383c4e0415SDaniel Scheller 	read_register_block(state,
5393c4e0415SDaniel Scheller 		(HYDRA_DMD_DVBS2_CRC_ERRORS_ADDR_OFFSET +
5403c4e0415SDaniel Scheller 		 HYDRA_DMD_STATUS_OFFSET(state->demod)),
5413c4e0415SDaniel Scheller 		(7 * sizeof(u32)),
5423c4e0415SDaniel Scheller 		(u8 *) &reg[0]);
5433c4e0415SDaniel Scheller 
5443c4e0415SDaniel Scheller 	switch (p->delivery_system) {
5453c4e0415SDaniel Scheller 	case SYS_DSS:
5463c4e0415SDaniel Scheller 	case SYS_DVBS:
5473c4e0415SDaniel Scheller 		p->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
5483c4e0415SDaniel Scheller 		p->post_bit_error.stat[0].uvalue = reg[5];
5493c4e0415SDaniel Scheller 		p->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
5503c4e0415SDaniel Scheller 		p->post_bit_count.stat[0].uvalue = reg[6];
5513c4e0415SDaniel Scheller 		break;
5523c4e0415SDaniel Scheller 	case SYS_DVBS2:
5533c4e0415SDaniel Scheller 		p->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
5543c4e0415SDaniel Scheller 		p->post_bit_error.stat[0].uvalue = reg[1];
5553c4e0415SDaniel Scheller 		p->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
5563c4e0415SDaniel Scheller 		p->post_bit_count.stat[0].uvalue = reg[2];
5573c4e0415SDaniel Scheller 		break;
5583c4e0415SDaniel Scheller 	default:
5593c4e0415SDaniel Scheller 		break;
5603c4e0415SDaniel Scheller 	}
5613c4e0415SDaniel Scheller 
5623c4e0415SDaniel Scheller 	mutex_unlock(&state->base->status_lock);
5633c4e0415SDaniel Scheller 
5643c4e0415SDaniel Scheller 	return 0;
5653c4e0415SDaniel Scheller }
5663c4e0415SDaniel Scheller 
5673c4e0415SDaniel Scheller static int read_signal_strength(struct dvb_frontend *fe)
5683c4e0415SDaniel Scheller {
5693c4e0415SDaniel Scheller 	struct mxl *state = fe->demodulator_priv;
5703c4e0415SDaniel Scheller 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
5713c4e0415SDaniel Scheller 	int stat;
5723c4e0415SDaniel Scheller 	u32 reg_data = 0;
5733c4e0415SDaniel Scheller 
5743c4e0415SDaniel Scheller 	mutex_lock(&state->base->status_lock);
5753c4e0415SDaniel Scheller 	HYDRA_DEMOD_STATUS_LOCK(state, state->demod);
5763c4e0415SDaniel Scheller 	stat = read_register(state, (HYDRA_DMD_STATUS_INPUT_POWER_ADDR +
5773c4e0415SDaniel Scheller 				     HYDRA_DMD_STATUS_OFFSET(state->demod)),
5783c4e0415SDaniel Scheller 			     &reg_data);
5793c4e0415SDaniel Scheller 	HYDRA_DEMOD_STATUS_UNLOCK(state, state->demod);
5803c4e0415SDaniel Scheller 	mutex_unlock(&state->base->status_lock);
5813c4e0415SDaniel Scheller 
5823c4e0415SDaniel Scheller 	p->strength.stat[0].scale = FE_SCALE_DECIBEL;
5833c4e0415SDaniel Scheller 	p->strength.stat[0].svalue = (s16) reg_data * 10; /* fix scale */
5843c4e0415SDaniel Scheller 
5853c4e0415SDaniel Scheller 	return stat;
5863c4e0415SDaniel Scheller }
5873c4e0415SDaniel Scheller 
5883c4e0415SDaniel Scheller static int read_status(struct dvb_frontend *fe, enum fe_status *status)
5893c4e0415SDaniel Scheller {
5903c4e0415SDaniel Scheller 	struct mxl *state = fe->demodulator_priv;
5913c4e0415SDaniel Scheller 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
5923c4e0415SDaniel Scheller 	u32 reg_data = 0;
5933c4e0415SDaniel Scheller 
5943c4e0415SDaniel Scheller 	mutex_lock(&state->base->status_lock);
5953c4e0415SDaniel Scheller 	HYDRA_DEMOD_STATUS_LOCK(state, state->demod);
5963c4e0415SDaniel Scheller 	read_register(state, (HYDRA_DMD_LOCK_STATUS_ADDR_OFFSET +
5973c4e0415SDaniel Scheller 			     HYDRA_DMD_STATUS_OFFSET(state->demod)),
5983c4e0415SDaniel Scheller 			     &reg_data);
5993c4e0415SDaniel Scheller 	HYDRA_DEMOD_STATUS_UNLOCK(state, state->demod);
6003c4e0415SDaniel Scheller 	mutex_unlock(&state->base->status_lock);
6013c4e0415SDaniel Scheller 
6023c4e0415SDaniel Scheller 	*status = (reg_data == 1) ? 0x1f : 0;
6033c4e0415SDaniel Scheller 
6043c4e0415SDaniel Scheller 	/* signal statistics */
6053c4e0415SDaniel Scheller 
6063c4e0415SDaniel Scheller 	/* signal strength is always available */
6073c4e0415SDaniel Scheller 	read_signal_strength(fe);
6083c4e0415SDaniel Scheller 
6093c4e0415SDaniel Scheller 	if (*status & FE_HAS_CARRIER)
6103c4e0415SDaniel Scheller 		read_snr(fe);
6113c4e0415SDaniel Scheller 	else
6123c4e0415SDaniel Scheller 		p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
6133c4e0415SDaniel Scheller 
6143c4e0415SDaniel Scheller 	if (*status & FE_HAS_SYNC)
6153c4e0415SDaniel Scheller 		read_ber(fe);
6163c4e0415SDaniel Scheller 	else {
6173c4e0415SDaniel Scheller 		p->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
6183c4e0415SDaniel Scheller 		p->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
6193c4e0415SDaniel Scheller 		p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
6203c4e0415SDaniel Scheller 		p->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
6213c4e0415SDaniel Scheller 	}
6223c4e0415SDaniel Scheller 
6233c4e0415SDaniel Scheller 	return 0;
6243c4e0415SDaniel Scheller }
6253c4e0415SDaniel Scheller 
6263c4e0415SDaniel Scheller static int tune(struct dvb_frontend *fe, bool re_tune,
6273c4e0415SDaniel Scheller 		unsigned int mode_flags,
6283c4e0415SDaniel Scheller 		unsigned int *delay, enum fe_status *status)
6293c4e0415SDaniel Scheller {
6303c4e0415SDaniel Scheller 	struct mxl *state = fe->demodulator_priv;
6313c4e0415SDaniel Scheller 	int r = 0;
6323c4e0415SDaniel Scheller 
6333c4e0415SDaniel Scheller 	*delay = HZ / 2;
6343c4e0415SDaniel Scheller 	if (re_tune) {
6353c4e0415SDaniel Scheller 		r = set_parameters(fe);
6363c4e0415SDaniel Scheller 		if (r)
6373c4e0415SDaniel Scheller 			return r;
6383c4e0415SDaniel Scheller 		state->tune_time = jiffies;
6393c4e0415SDaniel Scheller 		return 0;
6403c4e0415SDaniel Scheller 	}
6413c4e0415SDaniel Scheller 	if (*status & FE_HAS_LOCK)
6423c4e0415SDaniel Scheller 		return 0;
6433c4e0415SDaniel Scheller 
6443c4e0415SDaniel Scheller 	r = read_status(fe, status);
6453c4e0415SDaniel Scheller 	if (r)
6463c4e0415SDaniel Scheller 		return r;
6473c4e0415SDaniel Scheller 
6483c4e0415SDaniel Scheller 	return 0;
6493c4e0415SDaniel Scheller }
6503c4e0415SDaniel Scheller 
6513c4e0415SDaniel Scheller static enum fe_code_rate conv_fec(enum MXL_HYDRA_FEC_E fec)
6523c4e0415SDaniel Scheller {
6533c4e0415SDaniel Scheller 	enum fe_code_rate fec2fec[11] = {
6543c4e0415SDaniel Scheller 		FEC_NONE, FEC_1_2, FEC_3_5, FEC_2_3,
6553c4e0415SDaniel Scheller 		FEC_3_4, FEC_4_5, FEC_5_6, FEC_6_7,
6563c4e0415SDaniel Scheller 		FEC_7_8, FEC_8_9, FEC_9_10
6573c4e0415SDaniel Scheller 	};
6583c4e0415SDaniel Scheller 
6593c4e0415SDaniel Scheller 	if (fec > MXL_HYDRA_FEC_9_10)
6603c4e0415SDaniel Scheller 		return FEC_NONE;
6613c4e0415SDaniel Scheller 	return fec2fec[fec];
6623c4e0415SDaniel Scheller }
6633c4e0415SDaniel Scheller 
6643c4e0415SDaniel Scheller static int get_frontend(struct dvb_frontend *fe,
6653c4e0415SDaniel Scheller 			struct dtv_frontend_properties *p)
6663c4e0415SDaniel Scheller {
6673c4e0415SDaniel Scheller 	struct mxl *state = fe->demodulator_priv;
6683c4e0415SDaniel Scheller 	u32 reg_data[MXL_DEMOD_CHAN_PARAMS_BUFF_SIZE];
6693c4e0415SDaniel Scheller 	u32 freq;
6703c4e0415SDaniel Scheller 
6713c4e0415SDaniel Scheller 	mutex_lock(&state->base->status_lock);
6723c4e0415SDaniel Scheller 	HYDRA_DEMOD_STATUS_LOCK(state, state->demod);
6733c4e0415SDaniel Scheller 	read_register_block(state,
6743c4e0415SDaniel Scheller 		(HYDRA_DMD_STANDARD_ADDR_OFFSET +
6753c4e0415SDaniel Scheller 		HYDRA_DMD_STATUS_OFFSET(state->demod)),
6763c4e0415SDaniel Scheller 		(MXL_DEMOD_CHAN_PARAMS_BUFF_SIZE * 4), /* 25 * 4 bytes */
6773c4e0415SDaniel Scheller 		(u8 *) &reg_data[0]);
6783c4e0415SDaniel Scheller 	/* read demod channel parameters */
6793c4e0415SDaniel Scheller 	read_register_block(state,
6803c4e0415SDaniel Scheller 		(HYDRA_DMD_STATUS_CENTER_FREQ_IN_KHZ_ADDR +
6813c4e0415SDaniel Scheller 		HYDRA_DMD_STATUS_OFFSET(state->demod)),
6823c4e0415SDaniel Scheller 		(4), /* 4 bytes */
6833c4e0415SDaniel Scheller 		(u8 *) &freq);
6843c4e0415SDaniel Scheller 	HYDRA_DEMOD_STATUS_UNLOCK(state, state->demod);
6853c4e0415SDaniel Scheller 	mutex_unlock(&state->base->status_lock);
6863c4e0415SDaniel Scheller 
6873c4e0415SDaniel Scheller 	dev_dbg(state->i2cdev, "freq=%u delsys=%u srate=%u\n",
6883c4e0415SDaniel Scheller 		freq * 1000, reg_data[DMD_STANDARD_ADDR],
6893c4e0415SDaniel Scheller 		reg_data[DMD_SYMBOL_RATE_ADDR]);
6903c4e0415SDaniel Scheller 	p->symbol_rate = reg_data[DMD_SYMBOL_RATE_ADDR];
6913c4e0415SDaniel Scheller 	p->frequency = freq;
6923c4e0415SDaniel Scheller 	/*
6933c4e0415SDaniel Scheller 	 * p->delivery_system =
6943c4e0415SDaniel Scheller 	 *	(MXL_HYDRA_BCAST_STD_E) regData[DMD_STANDARD_ADDR];
6953c4e0415SDaniel Scheller 	 * p->inversion =
6963c4e0415SDaniel Scheller 	 *	(MXL_HYDRA_SPECTRUM_E) regData[DMD_SPECTRUM_INVERSION_ADDR];
6973c4e0415SDaniel Scheller 	 * freqSearchRangeKHz =
6983c4e0415SDaniel Scheller 	 *	(regData[DMD_FREQ_SEARCH_RANGE_IN_KHZ_ADDR]);
6993c4e0415SDaniel Scheller 	 */
7003c4e0415SDaniel Scheller 
7013c4e0415SDaniel Scheller 	p->fec_inner = conv_fec(reg_data[DMD_FEC_CODE_RATE_ADDR]);
7023c4e0415SDaniel Scheller 	switch (p->delivery_system) {
7033c4e0415SDaniel Scheller 	case SYS_DSS:
7043c4e0415SDaniel Scheller 		break;
7053c4e0415SDaniel Scheller 	case SYS_DVBS2:
7063c4e0415SDaniel Scheller 		switch ((enum MXL_HYDRA_PILOTS_E)
7073c4e0415SDaniel Scheller 			reg_data[DMD_DVBS2_PILOT_ON_OFF_ADDR]) {
7083c4e0415SDaniel Scheller 		case MXL_HYDRA_PILOTS_OFF:
7093c4e0415SDaniel Scheller 			p->pilot = PILOT_OFF;
7103c4e0415SDaniel Scheller 			break;
7113c4e0415SDaniel Scheller 		case MXL_HYDRA_PILOTS_ON:
7123c4e0415SDaniel Scheller 			p->pilot = PILOT_ON;
7133c4e0415SDaniel Scheller 			break;
7143c4e0415SDaniel Scheller 		default:
7153c4e0415SDaniel Scheller 			break;
7163c4e0415SDaniel Scheller 		}
7173c4e0415SDaniel Scheller 	case SYS_DVBS:
7183c4e0415SDaniel Scheller 		switch ((enum MXL_HYDRA_MODULATION_E)
7193c4e0415SDaniel Scheller 			reg_data[DMD_MODULATION_SCHEME_ADDR]) {
7203c4e0415SDaniel Scheller 		case MXL_HYDRA_MOD_QPSK:
7213c4e0415SDaniel Scheller 			p->modulation = QPSK;
7223c4e0415SDaniel Scheller 			break;
7233c4e0415SDaniel Scheller 		case MXL_HYDRA_MOD_8PSK:
7243c4e0415SDaniel Scheller 			p->modulation = PSK_8;
7253c4e0415SDaniel Scheller 			break;
7263c4e0415SDaniel Scheller 		default:
7273c4e0415SDaniel Scheller 			break;
7283c4e0415SDaniel Scheller 		}
7293c4e0415SDaniel Scheller 		switch ((enum MXL_HYDRA_ROLLOFF_E)
7303c4e0415SDaniel Scheller 			reg_data[DMD_SPECTRUM_ROLL_OFF_ADDR]) {
7313c4e0415SDaniel Scheller 		case MXL_HYDRA_ROLLOFF_0_20:
7323c4e0415SDaniel Scheller 			p->rolloff = ROLLOFF_20;
7333c4e0415SDaniel Scheller 			break;
7343c4e0415SDaniel Scheller 		case MXL_HYDRA_ROLLOFF_0_35:
7353c4e0415SDaniel Scheller 			p->rolloff = ROLLOFF_35;
7363c4e0415SDaniel Scheller 			break;
7373c4e0415SDaniel Scheller 		case MXL_HYDRA_ROLLOFF_0_25:
7383c4e0415SDaniel Scheller 			p->rolloff = ROLLOFF_25;
7393c4e0415SDaniel Scheller 			break;
7403c4e0415SDaniel Scheller 		default:
7413c4e0415SDaniel Scheller 			break;
7423c4e0415SDaniel Scheller 		}
7433c4e0415SDaniel Scheller 		break;
7443c4e0415SDaniel Scheller 	default:
7453c4e0415SDaniel Scheller 		return -EINVAL;
7463c4e0415SDaniel Scheller 	}
7473c4e0415SDaniel Scheller 	return 0;
7483c4e0415SDaniel Scheller }
7493c4e0415SDaniel Scheller 
7503c4e0415SDaniel Scheller static int set_input(struct dvb_frontend *fe, int input)
7513c4e0415SDaniel Scheller {
7523c4e0415SDaniel Scheller 	struct mxl *state = fe->demodulator_priv;
7533c4e0415SDaniel Scheller 
7543c4e0415SDaniel Scheller 	state->tuner = input;
7553c4e0415SDaniel Scheller 	return 0;
7563c4e0415SDaniel Scheller }
7573c4e0415SDaniel Scheller 
7583c4e0415SDaniel Scheller static struct dvb_frontend_ops mxl_ops = {
7593c4e0415SDaniel Scheller 	.delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS },
7603c4e0415SDaniel Scheller 	.info = {
7613c4e0415SDaniel Scheller 		.name			= "MaxLinear MxL5xx DVB-S/S2 tuner-demodulator",
7623c4e0415SDaniel Scheller 		.frequency_min		= 300000,
7633c4e0415SDaniel Scheller 		.frequency_max		= 2350000,
7643c4e0415SDaniel Scheller 		.frequency_stepsize	= 0,
7653c4e0415SDaniel Scheller 		.frequency_tolerance	= 0,
7663c4e0415SDaniel Scheller 		.symbol_rate_min	= 1000000,
7673c4e0415SDaniel Scheller 		.symbol_rate_max	= 45000000,
7683c4e0415SDaniel Scheller 		.caps			= FE_CAN_INVERSION_AUTO |
7693c4e0415SDaniel Scheller 					  FE_CAN_FEC_AUTO       |
7703c4e0415SDaniel Scheller 					  FE_CAN_QPSK           |
7713c4e0415SDaniel Scheller 					  FE_CAN_2G_MODULATION
7723c4e0415SDaniel Scheller 	},
7733c4e0415SDaniel Scheller 	.init				= init,
7743c4e0415SDaniel Scheller 	.release                        = release,
7753c4e0415SDaniel Scheller 	.get_frontend_algo              = get_algo,
7763c4e0415SDaniel Scheller 	.tune                           = tune,
7773c4e0415SDaniel Scheller 	.read_status			= read_status,
7783c4e0415SDaniel Scheller 	.sleep				= sleep,
7793c4e0415SDaniel Scheller 	.get_frontend                   = get_frontend,
7803c4e0415SDaniel Scheller 	.diseqc_send_master_cmd		= send_master_cmd,
7813c4e0415SDaniel Scheller };
7823c4e0415SDaniel Scheller 
7833c4e0415SDaniel Scheller static struct mxl_base *match_base(struct i2c_adapter  *i2c, u8 adr)
7843c4e0415SDaniel Scheller {
7853c4e0415SDaniel Scheller 	struct mxl_base *p;
7863c4e0415SDaniel Scheller 
7873c4e0415SDaniel Scheller 	list_for_each_entry(p, &mxllist, mxllist)
7883c4e0415SDaniel Scheller 		if (p->i2c == i2c && p->adr == adr)
7893c4e0415SDaniel Scheller 			return p;
7903c4e0415SDaniel Scheller 	return NULL;
7913c4e0415SDaniel Scheller }
7923c4e0415SDaniel Scheller 
7933c4e0415SDaniel Scheller static void cfg_dev_xtal(struct mxl *state, u32 freq, u32 cap, u32 enable)
7943c4e0415SDaniel Scheller {
7953c4e0415SDaniel Scheller 	if (state->base->can_clkout || !enable)
7963c4e0415SDaniel Scheller 		update_by_mnemonic(state, 0x90200054, 23, 1, enable);
7973c4e0415SDaniel Scheller 
7983c4e0415SDaniel Scheller 	if (freq == 24000000)
7993c4e0415SDaniel Scheller 		write_register(state, HYDRA_CRYSTAL_SETTING, 0);
8003c4e0415SDaniel Scheller 	else
8013c4e0415SDaniel Scheller 		write_register(state, HYDRA_CRYSTAL_SETTING, 1);
8023c4e0415SDaniel Scheller 
8033c4e0415SDaniel Scheller 	write_register(state, HYDRA_CRYSTAL_CAP, cap);
8043c4e0415SDaniel Scheller }
8053c4e0415SDaniel Scheller 
8063c4e0415SDaniel Scheller static u32 get_big_endian(u8 num_of_bits, const u8 buf[])
8073c4e0415SDaniel Scheller {
8083c4e0415SDaniel Scheller 	u32 ret_value = 0;
8093c4e0415SDaniel Scheller 
8103c4e0415SDaniel Scheller 	switch (num_of_bits) {
8113c4e0415SDaniel Scheller 	case 24:
8123c4e0415SDaniel Scheller 		ret_value = (((u32) buf[0]) << 16) |
8133c4e0415SDaniel Scheller 			(((u32) buf[1]) << 8) | buf[2];
8143c4e0415SDaniel Scheller 		break;
8153c4e0415SDaniel Scheller 	case 32:
8163c4e0415SDaniel Scheller 		ret_value = (((u32) buf[0]) << 24) |
8173c4e0415SDaniel Scheller 			(((u32) buf[1]) << 16) |
8183c4e0415SDaniel Scheller 			(((u32) buf[2]) << 8) | buf[3];
8193c4e0415SDaniel Scheller 		break;
8203c4e0415SDaniel Scheller 	default:
8213c4e0415SDaniel Scheller 		break;
8223c4e0415SDaniel Scheller 	}
8233c4e0415SDaniel Scheller 
8243c4e0415SDaniel Scheller 	return ret_value;
8253c4e0415SDaniel Scheller }
8263c4e0415SDaniel Scheller 
8273c4e0415SDaniel Scheller static int write_fw_segment(struct mxl *state,
8283c4e0415SDaniel Scheller 			    u32 mem_addr, u32 total_size, u8 *data_ptr)
8293c4e0415SDaniel Scheller {
8303c4e0415SDaniel Scheller 	int status;
8313c4e0415SDaniel Scheller 	u32 data_count = 0;
8323c4e0415SDaniel Scheller 	u32 size = 0;
8333c4e0415SDaniel Scheller 	u32 orig_size = 0;
8343c4e0415SDaniel Scheller 	u8 *w_buf_ptr = NULL;
8353c4e0415SDaniel Scheller 	u32 block_size = ((MXL_HYDRA_OEM_MAX_BLOCK_WRITE_LENGTH -
8363c4e0415SDaniel Scheller 			 (MXL_HYDRA_I2C_HDR_SIZE +
8373c4e0415SDaniel Scheller 			  MXL_HYDRA_REG_SIZE_IN_BYTES)) / 4) * 4;
8383c4e0415SDaniel Scheller 	u8 w_msg_buffer[MXL_HYDRA_OEM_MAX_BLOCK_WRITE_LENGTH -
8393c4e0415SDaniel Scheller 		      (MXL_HYDRA_I2C_HDR_SIZE + MXL_HYDRA_REG_SIZE_IN_BYTES)];
8403c4e0415SDaniel Scheller 
8413c4e0415SDaniel Scheller 	do {
8423c4e0415SDaniel Scheller 		size = orig_size = (((u32)(data_count + block_size)) > total_size) ?
8433c4e0415SDaniel Scheller 			(total_size - data_count) : block_size;
8443c4e0415SDaniel Scheller 
8453c4e0415SDaniel Scheller 		if (orig_size & 3)
8463c4e0415SDaniel Scheller 			size = (orig_size + 4) & ~3;
8473c4e0415SDaniel Scheller 		w_buf_ptr = &w_msg_buffer[0];
8483c4e0415SDaniel Scheller 		memset((void *) w_buf_ptr, 0, size);
8493c4e0415SDaniel Scheller 		memcpy((void *) w_buf_ptr, (void *) data_ptr, orig_size);
8503c4e0415SDaniel Scheller 		convert_endian(1, size, w_buf_ptr);
8513c4e0415SDaniel Scheller 		status  = write_firmware_block(state, mem_addr, size, w_buf_ptr);
8523c4e0415SDaniel Scheller 		if (status)
8533c4e0415SDaniel Scheller 			return status;
8543c4e0415SDaniel Scheller 		data_count += size;
8553c4e0415SDaniel Scheller 		mem_addr   += size;
8563c4e0415SDaniel Scheller 		data_ptr   += size;
8573c4e0415SDaniel Scheller 	} while (data_count < total_size);
8583c4e0415SDaniel Scheller 
8593c4e0415SDaniel Scheller 	return status;
8603c4e0415SDaniel Scheller }
8613c4e0415SDaniel Scheller 
8623c4e0415SDaniel Scheller static int do_firmware_download(struct mxl *state, u8 *mbin_buffer_ptr,
8633c4e0415SDaniel Scheller 				u32 mbin_buffer_size)
8643c4e0415SDaniel Scheller 
8653c4e0415SDaniel Scheller {
8663c4e0415SDaniel Scheller 	int status;
8673c4e0415SDaniel Scheller 	u32 index = 0;
8683c4e0415SDaniel Scheller 	u32 seg_length = 0;
8693c4e0415SDaniel Scheller 	u32 seg_address = 0;
8703c4e0415SDaniel Scheller 	struct MBIN_FILE_T *mbin_ptr  = (struct MBIN_FILE_T *)mbin_buffer_ptr;
8713c4e0415SDaniel Scheller 	struct MBIN_SEGMENT_T *segment_ptr;
8723c4e0415SDaniel Scheller 	enum MXL_BOOL_E xcpu_fw_flag = MXL_FALSE;
8733c4e0415SDaniel Scheller 
8743c4e0415SDaniel Scheller 	if (mbin_ptr->header.id != MBIN_FILE_HEADER_ID) {
8753c4e0415SDaniel Scheller 		dev_err(state->i2cdev, "%s: Invalid file header ID (%c)\n",
8763c4e0415SDaniel Scheller 		       __func__, mbin_ptr->header.id);
8773c4e0415SDaniel Scheller 		return -EINVAL;
8783c4e0415SDaniel Scheller 	}
8793c4e0415SDaniel Scheller 	status = write_register(state, FW_DL_SIGN_ADDR, 0);
8803c4e0415SDaniel Scheller 	if (status)
8813c4e0415SDaniel Scheller 		return status;
8823c4e0415SDaniel Scheller 	segment_ptr = (struct MBIN_SEGMENT_T *) (&mbin_ptr->data[0]);
8833c4e0415SDaniel Scheller 	for (index = 0; index < mbin_ptr->header.num_segments; index++) {
8843c4e0415SDaniel Scheller 		if (segment_ptr->header.id != MBIN_SEGMENT_HEADER_ID) {
8853c4e0415SDaniel Scheller 			dev_err(state->i2cdev, "%s: Invalid segment header ID (%c)\n",
8863c4e0415SDaniel Scheller 			       __func__, segment_ptr->header.id);
8873c4e0415SDaniel Scheller 			return -EINVAL;
8883c4e0415SDaniel Scheller 		}
8893c4e0415SDaniel Scheller 		seg_length  = get_big_endian(24,
8903c4e0415SDaniel Scheller 					    &(segment_ptr->header.len24[0]));
8913c4e0415SDaniel Scheller 		seg_address = get_big_endian(32,
8923c4e0415SDaniel Scheller 					    &(segment_ptr->header.address[0]));
8933c4e0415SDaniel Scheller 
8943c4e0415SDaniel Scheller 		if (state->base->type == MXL_HYDRA_DEVICE_568) {
8953c4e0415SDaniel Scheller 			if ((((seg_address & 0x90760000) == 0x90760000) ||
8963c4e0415SDaniel Scheller 			     ((seg_address & 0x90740000) == 0x90740000)) &&
8973c4e0415SDaniel Scheller 			    (xcpu_fw_flag == MXL_FALSE)) {
8983c4e0415SDaniel Scheller 				update_by_mnemonic(state, 0x8003003C, 0, 1, 1);
8993c4e0415SDaniel Scheller 				msleep(200);
9003c4e0415SDaniel Scheller 				write_register(state, 0x90720000, 0);
9013c4e0415SDaniel Scheller 				usleep_range(10000, 11000);
9023c4e0415SDaniel Scheller 				xcpu_fw_flag = MXL_TRUE;
9033c4e0415SDaniel Scheller 			}
9043c4e0415SDaniel Scheller 			status = write_fw_segment(state, seg_address,
9053c4e0415SDaniel Scheller 						  seg_length,
9063c4e0415SDaniel Scheller 						  (u8 *) segment_ptr->data);
9073c4e0415SDaniel Scheller 		} else {
9083c4e0415SDaniel Scheller 			if (((seg_address & 0x90760000) != 0x90760000) &&
9093c4e0415SDaniel Scheller 			    ((seg_address & 0x90740000) != 0x90740000))
9103c4e0415SDaniel Scheller 				status = write_fw_segment(state, seg_address,
9113c4e0415SDaniel Scheller 					seg_length, (u8 *) segment_ptr->data);
9123c4e0415SDaniel Scheller 		}
9133c4e0415SDaniel Scheller 		if (status)
9143c4e0415SDaniel Scheller 			return status;
9153c4e0415SDaniel Scheller 		segment_ptr = (struct MBIN_SEGMENT_T *)
9163c4e0415SDaniel Scheller 			&(segment_ptr->data[((seg_length + 3) / 4) * 4]);
9173c4e0415SDaniel Scheller 	}
9183c4e0415SDaniel Scheller 	return status;
9193c4e0415SDaniel Scheller }
9203c4e0415SDaniel Scheller 
9213c4e0415SDaniel Scheller static int check_fw(struct mxl *state, u8 *mbin, u32 mbin_len)
9223c4e0415SDaniel Scheller {
9233c4e0415SDaniel Scheller 	struct MBIN_FILE_HEADER_T *fh = (struct MBIN_FILE_HEADER_T *) mbin;
9243c4e0415SDaniel Scheller 	u32 flen = (fh->image_size24[0] << 16) |
9253c4e0415SDaniel Scheller 		(fh->image_size24[1] <<  8) | fh->image_size24[2];
9263c4e0415SDaniel Scheller 	u8 *fw, cs = 0;
9273c4e0415SDaniel Scheller 	u32 i;
9283c4e0415SDaniel Scheller 
9293c4e0415SDaniel Scheller 	if (fh->id != 'M' || fh->fmt_version != '1' || flen > 0x3FFF0) {
9303c4e0415SDaniel Scheller 		dev_info(state->i2cdev, "Invalid FW Header\n");
9313c4e0415SDaniel Scheller 		return -1;
9323c4e0415SDaniel Scheller 	}
9333c4e0415SDaniel Scheller 	fw = mbin + sizeof(struct MBIN_FILE_HEADER_T);
9343c4e0415SDaniel Scheller 	for (i = 0; i < flen; i += 1)
9353c4e0415SDaniel Scheller 		cs += fw[i];
9363c4e0415SDaniel Scheller 	if (cs != fh->image_checksum) {
9373c4e0415SDaniel Scheller 		dev_info(state->i2cdev, "Invalid FW Checksum\n");
9383c4e0415SDaniel Scheller 		return -1;
9393c4e0415SDaniel Scheller 	}
9403c4e0415SDaniel Scheller 	return 0;
9413c4e0415SDaniel Scheller }
9423c4e0415SDaniel Scheller 
9433c4e0415SDaniel Scheller static int firmware_download(struct mxl *state, u8 *mbin, u32 mbin_len)
9443c4e0415SDaniel Scheller {
9453c4e0415SDaniel Scheller 	int status;
9463c4e0415SDaniel Scheller 	u32 reg_data = 0;
9473c4e0415SDaniel Scheller 	struct MXL_HYDRA_SKU_COMMAND_T dev_sku_cfg;
9483c4e0415SDaniel Scheller 	u8 cmd_size = sizeof(struct MXL_HYDRA_SKU_COMMAND_T);
9493c4e0415SDaniel Scheller 	u8 cmd_buff[sizeof(struct MXL_HYDRA_SKU_COMMAND_T) + 6];
9503c4e0415SDaniel Scheller 
9513c4e0415SDaniel Scheller 	if (check_fw(state, mbin, mbin_len))
9523c4e0415SDaniel Scheller 		return -1;
9533c4e0415SDaniel Scheller 
9543c4e0415SDaniel Scheller 	/* put CPU into reset */
9553c4e0415SDaniel Scheller 	status = update_by_mnemonic(state, 0x8003003C, 0, 1, 0);
9563c4e0415SDaniel Scheller 	if (status)
9573c4e0415SDaniel Scheller 		return status;
9583c4e0415SDaniel Scheller 	usleep_range(1000, 2000);
9593c4e0415SDaniel Scheller 
9603c4e0415SDaniel Scheller 	/* Reset TX FIFO's, BBAND, XBAR */
9613c4e0415SDaniel Scheller 	status = write_register(state, HYDRA_RESET_TRANSPORT_FIFO_REG,
9623c4e0415SDaniel Scheller 				HYDRA_RESET_TRANSPORT_FIFO_DATA);
9633c4e0415SDaniel Scheller 	if (status)
9643c4e0415SDaniel Scheller 		return status;
9653c4e0415SDaniel Scheller 	status = write_register(state, HYDRA_RESET_BBAND_REG,
9663c4e0415SDaniel Scheller 				HYDRA_RESET_BBAND_DATA);
9673c4e0415SDaniel Scheller 	if (status)
9683c4e0415SDaniel Scheller 		return status;
9693c4e0415SDaniel Scheller 	status = write_register(state, HYDRA_RESET_XBAR_REG,
9703c4e0415SDaniel Scheller 				HYDRA_RESET_XBAR_DATA);
9713c4e0415SDaniel Scheller 	if (status)
9723c4e0415SDaniel Scheller 		return status;
9733c4e0415SDaniel Scheller 
9743c4e0415SDaniel Scheller 	/* Disable clock to Baseband, Wideband, SerDes,
9753c4e0415SDaniel Scheller 	 * Alias ext & Transport modules
9763c4e0415SDaniel Scheller 	 */
9773c4e0415SDaniel Scheller 	status = write_register(state, HYDRA_MODULES_CLK_2_REG,
9783c4e0415SDaniel Scheller 				HYDRA_DISABLE_CLK_2);
9793c4e0415SDaniel Scheller 	if (status)
9803c4e0415SDaniel Scheller 		return status;
9813c4e0415SDaniel Scheller 	/* Clear Software & Host interrupt status - (Clear on read) */
9823c4e0415SDaniel Scheller 	status = read_register(state, HYDRA_PRCM_ROOT_CLK_REG, &reg_data);
9833c4e0415SDaniel Scheller 	if (status)
9843c4e0415SDaniel Scheller 		return status;
9853c4e0415SDaniel Scheller 	status = do_firmware_download(state, mbin, mbin_len);
9863c4e0415SDaniel Scheller 	if (status)
9873c4e0415SDaniel Scheller 		return status;
9883c4e0415SDaniel Scheller 
9893c4e0415SDaniel Scheller 	if (state->base->type == MXL_HYDRA_DEVICE_568) {
9903c4e0415SDaniel Scheller 		usleep_range(10000, 11000);
9913c4e0415SDaniel Scheller 
9923c4e0415SDaniel Scheller 		/* bring XCPU out of reset */
9933c4e0415SDaniel Scheller 		status = write_register(state, 0x90720000, 1);
9943c4e0415SDaniel Scheller 		if (status)
9953c4e0415SDaniel Scheller 			return status;
9963c4e0415SDaniel Scheller 		msleep(500);
9973c4e0415SDaniel Scheller 
9983c4e0415SDaniel Scheller 		/* Enable XCPU UART message processing in MCPU */
9993c4e0415SDaniel Scheller 		status = write_register(state, 0x9076B510, 1);
10003c4e0415SDaniel Scheller 		if (status)
10013c4e0415SDaniel Scheller 			return status;
10023c4e0415SDaniel Scheller 	} else {
10033c4e0415SDaniel Scheller 		/* Bring CPU out of reset */
10043c4e0415SDaniel Scheller 		status = update_by_mnemonic(state, 0x8003003C, 0, 1, 1);
10053c4e0415SDaniel Scheller 		if (status)
10063c4e0415SDaniel Scheller 			return status;
10073c4e0415SDaniel Scheller 		/* Wait until FW boots */
10083c4e0415SDaniel Scheller 		msleep(150);
10093c4e0415SDaniel Scheller 	}
10103c4e0415SDaniel Scheller 
10113c4e0415SDaniel Scheller 	/* Initialize XPT XBAR */
10123c4e0415SDaniel Scheller 	status = write_register(state, XPT_DMD0_BASEADDR, 0x76543210);
10133c4e0415SDaniel Scheller 	if (status)
10143c4e0415SDaniel Scheller 		return status;
10153c4e0415SDaniel Scheller 
10163c4e0415SDaniel Scheller 	if (!firmware_is_alive(state))
10173c4e0415SDaniel Scheller 		return -1;
10183c4e0415SDaniel Scheller 
10193c4e0415SDaniel Scheller 	dev_info(state->i2cdev, "Hydra FW alive. Hail!\n");
10203c4e0415SDaniel Scheller 
10213c4e0415SDaniel Scheller 	/* sometimes register values are wrong shortly
10223c4e0415SDaniel Scheller 	 * after first heart beats
10233c4e0415SDaniel Scheller 	 */
10243c4e0415SDaniel Scheller 	msleep(50);
10253c4e0415SDaniel Scheller 
10263c4e0415SDaniel Scheller 	dev_sku_cfg.sku_type = state->base->sku_type;
10273c4e0415SDaniel Scheller 	BUILD_HYDRA_CMD(MXL_HYDRA_DEV_CFG_SKU_CMD, MXL_CMD_WRITE,
10283c4e0415SDaniel Scheller 			cmd_size, &dev_sku_cfg, cmd_buff);
10293c4e0415SDaniel Scheller 	status = send_command(state, cmd_size + MXL_HYDRA_CMD_HEADER_SIZE,
10303c4e0415SDaniel Scheller 			      &cmd_buff[0]);
10313c4e0415SDaniel Scheller 
10323c4e0415SDaniel Scheller 	return status;
10333c4e0415SDaniel Scheller }
10343c4e0415SDaniel Scheller 
10353c4e0415SDaniel Scheller static int cfg_ts_pad_mux(struct mxl *state, enum MXL_BOOL_E enable_serial_ts)
10363c4e0415SDaniel Scheller {
10373c4e0415SDaniel Scheller 	int status = 0;
10383c4e0415SDaniel Scheller 	u32 pad_mux_value = 0;
10393c4e0415SDaniel Scheller 
10403c4e0415SDaniel Scheller 	if (enable_serial_ts == MXL_TRUE) {
10413c4e0415SDaniel Scheller 		pad_mux_value = 0;
10423c4e0415SDaniel Scheller 		if ((state->base->type == MXL_HYDRA_DEVICE_541) ||
10433c4e0415SDaniel Scheller 		    (state->base->type == MXL_HYDRA_DEVICE_541S))
10443c4e0415SDaniel Scheller 			pad_mux_value = 2;
10453c4e0415SDaniel Scheller 	} else {
10463c4e0415SDaniel Scheller 		if ((state->base->type == MXL_HYDRA_DEVICE_581) ||
10473c4e0415SDaniel Scheller 		    (state->base->type == MXL_HYDRA_DEVICE_581S))
10483c4e0415SDaniel Scheller 			pad_mux_value = 2;
10493c4e0415SDaniel Scheller 		else
10503c4e0415SDaniel Scheller 			pad_mux_value = 3;
10513c4e0415SDaniel Scheller 	}
10523c4e0415SDaniel Scheller 
10533c4e0415SDaniel Scheller 	switch (state->base->type) {
10543c4e0415SDaniel Scheller 	case MXL_HYDRA_DEVICE_561:
10553c4e0415SDaniel Scheller 	case MXL_HYDRA_DEVICE_581:
10563c4e0415SDaniel Scheller 	case MXL_HYDRA_DEVICE_541:
10573c4e0415SDaniel Scheller 	case MXL_HYDRA_DEVICE_541S:
10583c4e0415SDaniel Scheller 	case MXL_HYDRA_DEVICE_561S:
10593c4e0415SDaniel Scheller 	case MXL_HYDRA_DEVICE_581S:
10603c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state, 0x90000170, 24, 3,
10613c4e0415SDaniel Scheller 					     pad_mux_value);
10623c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state, 0x90000170, 28, 3,
10633c4e0415SDaniel Scheller 					     pad_mux_value);
10643c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state, 0x90000174, 0, 3,
10653c4e0415SDaniel Scheller 					     pad_mux_value);
10663c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state, 0x90000174, 4, 3,
10673c4e0415SDaniel Scheller 					     pad_mux_value);
10683c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state, 0x90000174, 8, 3,
10693c4e0415SDaniel Scheller 					     pad_mux_value);
10703c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state, 0x90000174, 12, 3,
10713c4e0415SDaniel Scheller 					     pad_mux_value);
10723c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state, 0x90000174, 16, 3,
10733c4e0415SDaniel Scheller 					     pad_mux_value);
10743c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state, 0x90000174, 20, 3,
10753c4e0415SDaniel Scheller 					     pad_mux_value);
10763c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state, 0x90000174, 24, 3,
10773c4e0415SDaniel Scheller 					     pad_mux_value);
10783c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state, 0x90000174, 28, 3,
10793c4e0415SDaniel Scheller 					     pad_mux_value);
10803c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state, 0x90000178, 0, 3,
10813c4e0415SDaniel Scheller 					     pad_mux_value);
10823c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state, 0x90000178, 4, 3,
10833c4e0415SDaniel Scheller 					     pad_mux_value);
10843c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state, 0x90000178, 8, 3,
10853c4e0415SDaniel Scheller 					     pad_mux_value);
10863c4e0415SDaniel Scheller 		break;
10873c4e0415SDaniel Scheller 
10883c4e0415SDaniel Scheller 	case MXL_HYDRA_DEVICE_544:
10893c4e0415SDaniel Scheller 	case MXL_HYDRA_DEVICE_542:
10903c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state, 0x9000016C, 4, 3, 1);
10913c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state, 0x9000016C, 8, 3, 0);
10923c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state, 0x9000016C, 12, 3, 0);
10933c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state, 0x9000016C, 16, 3, 0);
10943c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state, 0x90000170, 0, 3, 0);
10953c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state, 0x90000178, 12, 3, 1);
10963c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state, 0x90000178, 16, 3, 1);
10973c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state, 0x90000178, 20, 3, 1);
10983c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state, 0x90000178, 24, 3, 1);
10993c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state, 0x9000017C, 0, 3, 1);
11003c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state, 0x9000017C, 4, 3, 1);
11013c4e0415SDaniel Scheller 		if (enable_serial_ts == MXL_ENABLE) {
11023c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11033c4e0415SDaniel Scheller 				0x90000170, 4, 3, 0);
11043c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11053c4e0415SDaniel Scheller 				0x90000170, 8, 3, 0);
11063c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11073c4e0415SDaniel Scheller 				0x90000170, 12, 3, 0);
11083c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11093c4e0415SDaniel Scheller 				0x90000170, 16, 3, 0);
11103c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11113c4e0415SDaniel Scheller 				0x90000170, 20, 3, 1);
11123c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11133c4e0415SDaniel Scheller 				0x90000170, 24, 3, 1);
11143c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11153c4e0415SDaniel Scheller 				0x90000170, 28, 3, 2);
11163c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11173c4e0415SDaniel Scheller 				0x90000174, 0, 3, 2);
11183c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11193c4e0415SDaniel Scheller 				0x90000174, 4, 3, 2);
11203c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11213c4e0415SDaniel Scheller 				0x90000174, 8, 3, 2);
11223c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11233c4e0415SDaniel Scheller 				0x90000174, 12, 3, 2);
11243c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11253c4e0415SDaniel Scheller 				0x90000174, 16, 3, 2);
11263c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11273c4e0415SDaniel Scheller 				0x90000174, 20, 3, 2);
11283c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11293c4e0415SDaniel Scheller 				0x90000174, 24, 3, 2);
11303c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11313c4e0415SDaniel Scheller 				0x90000174, 28, 3, 2);
11323c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11333c4e0415SDaniel Scheller 				0x90000178, 0, 3, 2);
11343c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11353c4e0415SDaniel Scheller 				0x90000178, 4, 3, 2);
11363c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11373c4e0415SDaniel Scheller 				0x90000178, 8, 3, 2);
11383c4e0415SDaniel Scheller 		} else {
11393c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11403c4e0415SDaniel Scheller 				0x90000170, 4, 3, 3);
11413c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11423c4e0415SDaniel Scheller 				0x90000170, 8, 3, 3);
11433c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11443c4e0415SDaniel Scheller 				0x90000170, 12, 3, 3);
11453c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11463c4e0415SDaniel Scheller 				0x90000170, 16, 3, 3);
11473c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11483c4e0415SDaniel Scheller 				0x90000170, 20, 3, 3);
11493c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11503c4e0415SDaniel Scheller 				0x90000170, 24, 3, 3);
11513c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11523c4e0415SDaniel Scheller 				0x90000170, 28, 3, 3);
11533c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11543c4e0415SDaniel Scheller 				0x90000174, 0, 3, 3);
11553c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11563c4e0415SDaniel Scheller 				0x90000174, 4, 3, 3);
11573c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11583c4e0415SDaniel Scheller 				0x90000174, 8, 3, 3);
11593c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11603c4e0415SDaniel Scheller 				0x90000174, 12, 3, 3);
11613c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11623c4e0415SDaniel Scheller 				0x90000174, 16, 3, 3);
11633c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11643c4e0415SDaniel Scheller 				0x90000174, 20, 3, 1);
11653c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11663c4e0415SDaniel Scheller 				0x90000174, 24, 3, 1);
11673c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11683c4e0415SDaniel Scheller 				0x90000174, 28, 3, 1);
11693c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11703c4e0415SDaniel Scheller 				0x90000178, 0, 3, 1);
11713c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11723c4e0415SDaniel Scheller 				0x90000178, 4, 3, 1);
11733c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11743c4e0415SDaniel Scheller 				0x90000178, 8, 3, 1);
11753c4e0415SDaniel Scheller 		}
11763c4e0415SDaniel Scheller 		break;
11773c4e0415SDaniel Scheller 
11783c4e0415SDaniel Scheller 	case MXL_HYDRA_DEVICE_568:
11793c4e0415SDaniel Scheller 		if (enable_serial_ts == MXL_FALSE) {
11803c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11813c4e0415SDaniel Scheller 				0x9000016C, 8, 3, 5);
11823c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11833c4e0415SDaniel Scheller 				0x9000016C, 12, 3, 5);
11843c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11853c4e0415SDaniel Scheller 				0x9000016C, 16, 3, 5);
11863c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11873c4e0415SDaniel Scheller 				0x9000016C, 20, 3, 5);
11883c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11893c4e0415SDaniel Scheller 				0x9000016C, 24, 3, 5);
11903c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11913c4e0415SDaniel Scheller 				0x9000016C, 28, 3, 5);
11923c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11933c4e0415SDaniel Scheller 				0x90000170, 0, 3, 5);
11943c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11953c4e0415SDaniel Scheller 				0x90000170, 4, 3, 5);
11963c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11973c4e0415SDaniel Scheller 				0x90000170, 8, 3, 5);
11983c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
11993c4e0415SDaniel Scheller 				0x90000170, 12, 3, 5);
12003c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
12013c4e0415SDaniel Scheller 				0x90000170, 16, 3, 5);
12023c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
12033c4e0415SDaniel Scheller 				0x90000170, 20, 3, 5);
12043c4e0415SDaniel Scheller 
12053c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
12063c4e0415SDaniel Scheller 				0x90000170, 24, 3, pad_mux_value);
12073c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
12083c4e0415SDaniel Scheller 				0x90000174, 0, 3, pad_mux_value);
12093c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
12103c4e0415SDaniel Scheller 				0x90000174, 4, 3, pad_mux_value);
12113c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
12123c4e0415SDaniel Scheller 				0x90000174, 8, 3, pad_mux_value);
12133c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
12143c4e0415SDaniel Scheller 				0x90000174, 12, 3, pad_mux_value);
12153c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
12163c4e0415SDaniel Scheller 				0x90000174, 16, 3, pad_mux_value);
12173c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
12183c4e0415SDaniel Scheller 				0x90000174, 20, 3, pad_mux_value);
12193c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
12203c4e0415SDaniel Scheller 				0x90000174, 24, 3, pad_mux_value);
12213c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
12223c4e0415SDaniel Scheller 				0x90000174, 28, 3, pad_mux_value);
12233c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
12243c4e0415SDaniel Scheller 				0x90000178, 0, 3, pad_mux_value);
12253c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
12263c4e0415SDaniel Scheller 				0x90000178, 4, 3, pad_mux_value);
12273c4e0415SDaniel Scheller 
12283c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
12293c4e0415SDaniel Scheller 				0x90000178, 8, 3, 5);
12303c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
12313c4e0415SDaniel Scheller 				0x90000178, 12, 3, 5);
12323c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
12333c4e0415SDaniel Scheller 				0x90000178, 16, 3, 5);
12343c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
12353c4e0415SDaniel Scheller 				0x90000178, 20, 3, 5);
12363c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
12373c4e0415SDaniel Scheller 				0x90000178, 24, 3, 5);
12383c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
12393c4e0415SDaniel Scheller 				0x90000178, 28, 3, 5);
12403c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
12413c4e0415SDaniel Scheller 				0x9000017C, 0, 3, 5);
12423c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
12433c4e0415SDaniel Scheller 				0x9000017C, 4, 3, 5);
12443c4e0415SDaniel Scheller 		} else {
12453c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
12463c4e0415SDaniel Scheller 				0x90000170, 4, 3, pad_mux_value);
12473c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
12483c4e0415SDaniel Scheller 				0x90000170, 8, 3, pad_mux_value);
12493c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
12503c4e0415SDaniel Scheller 				0x90000170, 12, 3, pad_mux_value);
12513c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
12523c4e0415SDaniel Scheller 				0x90000170, 16, 3, pad_mux_value);
12533c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
12543c4e0415SDaniel Scheller 				0x90000170, 20, 3, pad_mux_value);
12553c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
12563c4e0415SDaniel Scheller 				0x90000170, 24, 3, pad_mux_value);
12573c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
12583c4e0415SDaniel Scheller 				0x90000170, 28, 3, pad_mux_value);
12593c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
12603c4e0415SDaniel Scheller 				0x90000174, 0, 3, pad_mux_value);
12613c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
12623c4e0415SDaniel Scheller 				0x90000174, 4, 3, pad_mux_value);
12633c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
12643c4e0415SDaniel Scheller 				0x90000174, 8, 3, pad_mux_value);
12653c4e0415SDaniel Scheller 			status |= update_by_mnemonic(state,
12663c4e0415SDaniel Scheller 				0x90000174, 12, 3, pad_mux_value);
12673c4e0415SDaniel Scheller 		}
12683c4e0415SDaniel Scheller 		break;
12693c4e0415SDaniel Scheller 
12703c4e0415SDaniel Scheller 
12713c4e0415SDaniel Scheller 	case MXL_HYDRA_DEVICE_584:
12723c4e0415SDaniel Scheller 	default:
12733c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state,
12743c4e0415SDaniel Scheller 			0x90000170, 4, 3, pad_mux_value);
12753c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state,
12763c4e0415SDaniel Scheller 			0x90000170, 8, 3, pad_mux_value);
12773c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state,
12783c4e0415SDaniel Scheller 			0x90000170, 12, 3, pad_mux_value);
12793c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state,
12803c4e0415SDaniel Scheller 			0x90000170, 16, 3, pad_mux_value);
12813c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state,
12823c4e0415SDaniel Scheller 			0x90000170, 20, 3, pad_mux_value);
12833c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state,
12843c4e0415SDaniel Scheller 			0x90000170, 24, 3, pad_mux_value);
12853c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state,
12863c4e0415SDaniel Scheller 			0x90000170, 28, 3, pad_mux_value);
12873c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state,
12883c4e0415SDaniel Scheller 			0x90000174, 0, 3, pad_mux_value);
12893c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state,
12903c4e0415SDaniel Scheller 			0x90000174, 4, 3, pad_mux_value);
12913c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state,
12923c4e0415SDaniel Scheller 			0x90000174, 8, 3, pad_mux_value);
12933c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state,
12943c4e0415SDaniel Scheller 			0x90000174, 12, 3, pad_mux_value);
12953c4e0415SDaniel Scheller 		break;
12963c4e0415SDaniel Scheller 	}
12973c4e0415SDaniel Scheller 	return status;
12983c4e0415SDaniel Scheller }
12993c4e0415SDaniel Scheller 
13003c4e0415SDaniel Scheller static int set_drive_strength(struct mxl *state,
13013c4e0415SDaniel Scheller 		enum MXL_HYDRA_TS_DRIVE_STRENGTH_E ts_drive_strength)
13023c4e0415SDaniel Scheller {
13033c4e0415SDaniel Scheller 	int stat = 0;
13043c4e0415SDaniel Scheller 	u32 val;
13053c4e0415SDaniel Scheller 
13063c4e0415SDaniel Scheller 	read_register(state, 0x90000194, &val);
13073c4e0415SDaniel Scheller 	dev_info(state->i2cdev, "DIGIO = %08x\n", val);
13083c4e0415SDaniel Scheller 	dev_info(state->i2cdev, "set drive_strength = %u\n", ts_drive_strength);
13093c4e0415SDaniel Scheller 
13103c4e0415SDaniel Scheller 
13113c4e0415SDaniel Scheller 	stat |= update_by_mnemonic(state, 0x90000194, 0, 3, ts_drive_strength);
13123c4e0415SDaniel Scheller 	stat |= update_by_mnemonic(state, 0x90000194, 20, 3, ts_drive_strength);
13133c4e0415SDaniel Scheller 	stat |= update_by_mnemonic(state, 0x90000194, 24, 3, ts_drive_strength);
13143c4e0415SDaniel Scheller 	stat |= update_by_mnemonic(state, 0x90000198, 12, 3, ts_drive_strength);
13153c4e0415SDaniel Scheller 	stat |= update_by_mnemonic(state, 0x90000198, 16, 3, ts_drive_strength);
13163c4e0415SDaniel Scheller 	stat |= update_by_mnemonic(state, 0x90000198, 20, 3, ts_drive_strength);
13173c4e0415SDaniel Scheller 	stat |= update_by_mnemonic(state, 0x90000198, 24, 3, ts_drive_strength);
13183c4e0415SDaniel Scheller 	stat |= update_by_mnemonic(state, 0x9000019C, 0, 3, ts_drive_strength);
13193c4e0415SDaniel Scheller 	stat |= update_by_mnemonic(state, 0x9000019C, 4, 3, ts_drive_strength);
13203c4e0415SDaniel Scheller 	stat |= update_by_mnemonic(state, 0x9000019C, 8, 3, ts_drive_strength);
13213c4e0415SDaniel Scheller 	stat |= update_by_mnemonic(state, 0x9000019C, 24, 3, ts_drive_strength);
13223c4e0415SDaniel Scheller 	stat |= update_by_mnemonic(state, 0x9000019C, 28, 3, ts_drive_strength);
13233c4e0415SDaniel Scheller 	stat |= update_by_mnemonic(state, 0x900001A0, 0, 3, ts_drive_strength);
13243c4e0415SDaniel Scheller 	stat |= update_by_mnemonic(state, 0x900001A0, 4, 3, ts_drive_strength);
13253c4e0415SDaniel Scheller 	stat |= update_by_mnemonic(state, 0x900001A0, 20, 3, ts_drive_strength);
13263c4e0415SDaniel Scheller 	stat |= update_by_mnemonic(state, 0x900001A0, 24, 3, ts_drive_strength);
13273c4e0415SDaniel Scheller 	stat |= update_by_mnemonic(state, 0x900001A0, 28, 3, ts_drive_strength);
13283c4e0415SDaniel Scheller 
13293c4e0415SDaniel Scheller 	return stat;
13303c4e0415SDaniel Scheller }
13313c4e0415SDaniel Scheller 
13323c4e0415SDaniel Scheller static int enable_tuner(struct mxl *state, u32 tuner, u32 enable)
13333c4e0415SDaniel Scheller {
13343c4e0415SDaniel Scheller 	int stat = 0;
13353c4e0415SDaniel Scheller 	struct MXL_HYDRA_TUNER_CMD ctrl_tuner_cmd;
13363c4e0415SDaniel Scheller 	u8 cmd_size = sizeof(ctrl_tuner_cmd);
13373c4e0415SDaniel Scheller 	u8 cmd_buff[MXL_HYDRA_OEM_MAX_CMD_BUFF_LEN];
13383c4e0415SDaniel Scheller 	u32 val, count = 10;
13393c4e0415SDaniel Scheller 
13403c4e0415SDaniel Scheller 	ctrl_tuner_cmd.tuner_id = tuner;
13413c4e0415SDaniel Scheller 	ctrl_tuner_cmd.enable = enable;
13423c4e0415SDaniel Scheller 	BUILD_HYDRA_CMD(MXL_HYDRA_TUNER_ACTIVATE_CMD, MXL_CMD_WRITE,
13433c4e0415SDaniel Scheller 			cmd_size, &ctrl_tuner_cmd, cmd_buff);
13443c4e0415SDaniel Scheller 	stat = send_command(state, cmd_size + MXL_HYDRA_CMD_HEADER_SIZE,
13453c4e0415SDaniel Scheller 			    &cmd_buff[0]);
13463c4e0415SDaniel Scheller 	if (stat)
13473c4e0415SDaniel Scheller 		return stat;
13483c4e0415SDaniel Scheller 	read_register(state, HYDRA_TUNER_ENABLE_COMPLETE, &val);
13493c4e0415SDaniel Scheller 	while (--count && ((val >> tuner) & 1) != enable) {
13503c4e0415SDaniel Scheller 		msleep(20);
13513c4e0415SDaniel Scheller 		read_register(state, HYDRA_TUNER_ENABLE_COMPLETE, &val);
13523c4e0415SDaniel Scheller 	}
13533c4e0415SDaniel Scheller 	if (!count)
13543c4e0415SDaniel Scheller 		return -1;
13553c4e0415SDaniel Scheller 	read_register(state, HYDRA_TUNER_ENABLE_COMPLETE, &val);
13563c4e0415SDaniel Scheller 	dev_dbg(state->i2cdev, "tuner %u ready = %u\n",
13573c4e0415SDaniel Scheller 		tuner, (val >> tuner) & 1);
13583c4e0415SDaniel Scheller 
13593c4e0415SDaniel Scheller 	return 0;
13603c4e0415SDaniel Scheller }
13613c4e0415SDaniel Scheller 
13623c4e0415SDaniel Scheller 
13633c4e0415SDaniel Scheller static int config_ts(struct mxl *state, enum MXL_HYDRA_DEMOD_ID_E demod_id,
13643c4e0415SDaniel Scheller 		     struct MXL_HYDRA_MPEGOUT_PARAM_T *mpeg_out_param_ptr)
13653c4e0415SDaniel Scheller {
13663c4e0415SDaniel Scheller 	int status = 0;
13673c4e0415SDaniel Scheller 	u32 nco_count_min = 0;
13683c4e0415SDaniel Scheller 	u32 clk_type = 0;
13693c4e0415SDaniel Scheller 
13703c4e0415SDaniel Scheller 	struct MXL_REG_FIELD_T xpt_sync_polarity[MXL_HYDRA_DEMOD_MAX] = {
13713c4e0415SDaniel Scheller 		{0x90700010, 8, 1}, {0x90700010, 9, 1},
13723c4e0415SDaniel Scheller 		{0x90700010, 10, 1}, {0x90700010, 11, 1},
13733c4e0415SDaniel Scheller 		{0x90700010, 12, 1}, {0x90700010, 13, 1},
13743c4e0415SDaniel Scheller 		{0x90700010, 14, 1}, {0x90700010, 15, 1} };
13753c4e0415SDaniel Scheller 	struct MXL_REG_FIELD_T xpt_clock_polarity[MXL_HYDRA_DEMOD_MAX] = {
13763c4e0415SDaniel Scheller 		{0x90700010, 16, 1}, {0x90700010, 17, 1},
13773c4e0415SDaniel Scheller 		{0x90700010, 18, 1}, {0x90700010, 19, 1},
13783c4e0415SDaniel Scheller 		{0x90700010, 20, 1}, {0x90700010, 21, 1},
13793c4e0415SDaniel Scheller 		{0x90700010, 22, 1}, {0x90700010, 23, 1} };
13803c4e0415SDaniel Scheller 	struct MXL_REG_FIELD_T xpt_valid_polarity[MXL_HYDRA_DEMOD_MAX] = {
13813c4e0415SDaniel Scheller 		{0x90700014, 0, 1}, {0x90700014, 1, 1},
13823c4e0415SDaniel Scheller 		{0x90700014, 2, 1}, {0x90700014, 3, 1},
13833c4e0415SDaniel Scheller 		{0x90700014, 4, 1}, {0x90700014, 5, 1},
13843c4e0415SDaniel Scheller 		{0x90700014, 6, 1}, {0x90700014, 7, 1} };
13853c4e0415SDaniel Scheller 	struct MXL_REG_FIELD_T xpt_ts_clock_phase[MXL_HYDRA_DEMOD_MAX] = {
13863c4e0415SDaniel Scheller 		{0x90700018, 0, 3}, {0x90700018, 4, 3},
13873c4e0415SDaniel Scheller 		{0x90700018, 8, 3}, {0x90700018, 12, 3},
13883c4e0415SDaniel Scheller 		{0x90700018, 16, 3}, {0x90700018, 20, 3},
13893c4e0415SDaniel Scheller 		{0x90700018, 24, 3}, {0x90700018, 28, 3} };
13903c4e0415SDaniel Scheller 	struct MXL_REG_FIELD_T xpt_lsb_first[MXL_HYDRA_DEMOD_MAX] = {
13913c4e0415SDaniel Scheller 		{0x9070000C, 16, 1}, {0x9070000C, 17, 1},
13923c4e0415SDaniel Scheller 		{0x9070000C, 18, 1}, {0x9070000C, 19, 1},
13933c4e0415SDaniel Scheller 		{0x9070000C, 20, 1}, {0x9070000C, 21, 1},
13943c4e0415SDaniel Scheller 		{0x9070000C, 22, 1}, {0x9070000C, 23, 1} };
13953c4e0415SDaniel Scheller 	struct MXL_REG_FIELD_T xpt_sync_byte[MXL_HYDRA_DEMOD_MAX] = {
13963c4e0415SDaniel Scheller 		{0x90700010, 0, 1}, {0x90700010, 1, 1},
13973c4e0415SDaniel Scheller 		{0x90700010, 2, 1}, {0x90700010, 3, 1},
13983c4e0415SDaniel Scheller 		{0x90700010, 4, 1}, {0x90700010, 5, 1},
13993c4e0415SDaniel Scheller 		{0x90700010, 6, 1}, {0x90700010, 7, 1} };
14003c4e0415SDaniel Scheller 	struct MXL_REG_FIELD_T xpt_enable_output[MXL_HYDRA_DEMOD_MAX] = {
14013c4e0415SDaniel Scheller 		{0x9070000C, 0, 1}, {0x9070000C, 1, 1},
14023c4e0415SDaniel Scheller 		{0x9070000C, 2, 1}, {0x9070000C, 3, 1},
14033c4e0415SDaniel Scheller 		{0x9070000C, 4, 1}, {0x9070000C, 5, 1},
14043c4e0415SDaniel Scheller 		{0x9070000C, 6, 1}, {0x9070000C, 7, 1} };
14053c4e0415SDaniel Scheller 	struct MXL_REG_FIELD_T xpt_err_replace_sync[MXL_HYDRA_DEMOD_MAX] = {
14063c4e0415SDaniel Scheller 		{0x9070000C, 24, 1}, {0x9070000C, 25, 1},
14073c4e0415SDaniel Scheller 		{0x9070000C, 26, 1}, {0x9070000C, 27, 1},
14083c4e0415SDaniel Scheller 		{0x9070000C, 28, 1}, {0x9070000C, 29, 1},
14093c4e0415SDaniel Scheller 		{0x9070000C, 30, 1}, {0x9070000C, 31, 1} };
14103c4e0415SDaniel Scheller 	struct MXL_REG_FIELD_T xpt_err_replace_valid[MXL_HYDRA_DEMOD_MAX] = {
14113c4e0415SDaniel Scheller 		{0x90700014, 8, 1}, {0x90700014, 9, 1},
14123c4e0415SDaniel Scheller 		{0x90700014, 10, 1}, {0x90700014, 11, 1},
14133c4e0415SDaniel Scheller 		{0x90700014, 12, 1}, {0x90700014, 13, 1},
14143c4e0415SDaniel Scheller 		{0x90700014, 14, 1}, {0x90700014, 15, 1} };
14153c4e0415SDaniel Scheller 	struct MXL_REG_FIELD_T xpt_continuous_clock[MXL_HYDRA_DEMOD_MAX] = {
14163c4e0415SDaniel Scheller 		{0x907001D4, 0, 1}, {0x907001D4, 1, 1},
14173c4e0415SDaniel Scheller 		{0x907001D4, 2, 1}, {0x907001D4, 3, 1},
14183c4e0415SDaniel Scheller 		{0x907001D4, 4, 1}, {0x907001D4, 5, 1},
14193c4e0415SDaniel Scheller 		{0x907001D4, 6, 1}, {0x907001D4, 7, 1} };
14203c4e0415SDaniel Scheller 	struct MXL_REG_FIELD_T xpt_nco_clock_rate[MXL_HYDRA_DEMOD_MAX] = {
14213c4e0415SDaniel Scheller 		{0x90700044, 16, 80}, {0x90700044, 16, 81},
14223c4e0415SDaniel Scheller 		{0x90700044, 16, 82}, {0x90700044, 16, 83},
14233c4e0415SDaniel Scheller 		{0x90700044, 16, 84}, {0x90700044, 16, 85},
14243c4e0415SDaniel Scheller 		{0x90700044, 16, 86}, {0x90700044, 16, 87} };
14253c4e0415SDaniel Scheller 
14263c4e0415SDaniel Scheller 	demod_id = state->base->ts_map[demod_id];
14273c4e0415SDaniel Scheller 
14283c4e0415SDaniel Scheller 	if (mpeg_out_param_ptr->enable == MXL_ENABLE) {
14293c4e0415SDaniel Scheller 		if (mpeg_out_param_ptr->mpeg_mode ==
14303c4e0415SDaniel Scheller 		    MXL_HYDRA_MPEG_MODE_PARALLEL) {
14313c4e0415SDaniel Scheller 		} else {
14323c4e0415SDaniel Scheller 			cfg_ts_pad_mux(state, MXL_TRUE);
14333c4e0415SDaniel Scheller 			update_by_mnemonic(state,
14343c4e0415SDaniel Scheller 				0x90700010, 27, 1, MXL_FALSE);
14353c4e0415SDaniel Scheller 		}
14363c4e0415SDaniel Scheller 	}
14373c4e0415SDaniel Scheller 
14383c4e0415SDaniel Scheller 	nco_count_min =
14393c4e0415SDaniel Scheller 		(u32)(MXL_HYDRA_NCO_CLK / mpeg_out_param_ptr->max_mpeg_clk_rate);
14403c4e0415SDaniel Scheller 
14413c4e0415SDaniel Scheller 	if (state->base->chipversion >= 2) {
14423c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state,
14433c4e0415SDaniel Scheller 			xpt_nco_clock_rate[demod_id].reg_addr, /* Reg Addr */
14443c4e0415SDaniel Scheller 			xpt_nco_clock_rate[demod_id].lsb_pos, /* LSB pos */
14453c4e0415SDaniel Scheller 			xpt_nco_clock_rate[demod_id].num_of_bits, /* Num of bits */
14463c4e0415SDaniel Scheller 			nco_count_min); /* Data */
14473c4e0415SDaniel Scheller 	} else
14483c4e0415SDaniel Scheller 		update_by_mnemonic(state, 0x90700044, 16, 8, nco_count_min);
14493c4e0415SDaniel Scheller 
14503c4e0415SDaniel Scheller 	if (mpeg_out_param_ptr->mpeg_clk_type == MXL_HYDRA_MPEG_CLK_CONTINUOUS)
14513c4e0415SDaniel Scheller 		clk_type = 1;
14523c4e0415SDaniel Scheller 
14533c4e0415SDaniel Scheller 	if (mpeg_out_param_ptr->mpeg_mode < MXL_HYDRA_MPEG_MODE_PARALLEL) {
14543c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state,
14553c4e0415SDaniel Scheller 			xpt_continuous_clock[demod_id].reg_addr,
14563c4e0415SDaniel Scheller 			xpt_continuous_clock[demod_id].lsb_pos,
14573c4e0415SDaniel Scheller 			xpt_continuous_clock[demod_id].num_of_bits,
14583c4e0415SDaniel Scheller 			clk_type);
14593c4e0415SDaniel Scheller 	} else
14603c4e0415SDaniel Scheller 		update_by_mnemonic(state, 0x907001D4, 8, 1, clk_type);
14613c4e0415SDaniel Scheller 
14623c4e0415SDaniel Scheller 	status |= update_by_mnemonic(state,
14633c4e0415SDaniel Scheller 		xpt_sync_polarity[demod_id].reg_addr,
14643c4e0415SDaniel Scheller 		xpt_sync_polarity[demod_id].lsb_pos,
14653c4e0415SDaniel Scheller 		xpt_sync_polarity[demod_id].num_of_bits,
14663c4e0415SDaniel Scheller 		mpeg_out_param_ptr->mpeg_sync_pol);
14673c4e0415SDaniel Scheller 
14683c4e0415SDaniel Scheller 	status |= update_by_mnemonic(state,
14693c4e0415SDaniel Scheller 		xpt_valid_polarity[demod_id].reg_addr,
14703c4e0415SDaniel Scheller 		xpt_valid_polarity[demod_id].lsb_pos,
14713c4e0415SDaniel Scheller 		xpt_valid_polarity[demod_id].num_of_bits,
14723c4e0415SDaniel Scheller 		mpeg_out_param_ptr->mpeg_valid_pol);
14733c4e0415SDaniel Scheller 
14743c4e0415SDaniel Scheller 	status |= update_by_mnemonic(state,
14753c4e0415SDaniel Scheller 		xpt_clock_polarity[demod_id].reg_addr,
14763c4e0415SDaniel Scheller 		xpt_clock_polarity[demod_id].lsb_pos,
14773c4e0415SDaniel Scheller 		xpt_clock_polarity[demod_id].num_of_bits,
14783c4e0415SDaniel Scheller 		mpeg_out_param_ptr->mpeg_clk_pol);
14793c4e0415SDaniel Scheller 
14803c4e0415SDaniel Scheller 	status |= update_by_mnemonic(state,
14813c4e0415SDaniel Scheller 		xpt_sync_byte[demod_id].reg_addr,
14823c4e0415SDaniel Scheller 		xpt_sync_byte[demod_id].lsb_pos,
14833c4e0415SDaniel Scheller 		xpt_sync_byte[demod_id].num_of_bits,
14843c4e0415SDaniel Scheller 		mpeg_out_param_ptr->mpeg_sync_pulse_width);
14853c4e0415SDaniel Scheller 
14863c4e0415SDaniel Scheller 	status |= update_by_mnemonic(state,
14873c4e0415SDaniel Scheller 		xpt_ts_clock_phase[demod_id].reg_addr,
14883c4e0415SDaniel Scheller 		xpt_ts_clock_phase[demod_id].lsb_pos,
14893c4e0415SDaniel Scheller 		xpt_ts_clock_phase[demod_id].num_of_bits,
14903c4e0415SDaniel Scheller 		mpeg_out_param_ptr->mpeg_clk_phase);
14913c4e0415SDaniel Scheller 
14923c4e0415SDaniel Scheller 	status |= update_by_mnemonic(state,
14933c4e0415SDaniel Scheller 		xpt_lsb_first[demod_id].reg_addr,
14943c4e0415SDaniel Scheller 		xpt_lsb_first[demod_id].lsb_pos,
14953c4e0415SDaniel Scheller 		xpt_lsb_first[demod_id].num_of_bits,
14963c4e0415SDaniel Scheller 		mpeg_out_param_ptr->lsb_or_msb_first);
14973c4e0415SDaniel Scheller 
14983c4e0415SDaniel Scheller 	switch (mpeg_out_param_ptr->mpeg_error_indication) {
14993c4e0415SDaniel Scheller 	case MXL_HYDRA_MPEG_ERR_REPLACE_SYNC:
15003c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state,
15013c4e0415SDaniel Scheller 			xpt_err_replace_sync[demod_id].reg_addr,
15023c4e0415SDaniel Scheller 			xpt_err_replace_sync[demod_id].lsb_pos,
15033c4e0415SDaniel Scheller 			xpt_err_replace_sync[demod_id].num_of_bits,
15043c4e0415SDaniel Scheller 			MXL_TRUE);
15053c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state,
15063c4e0415SDaniel Scheller 			xpt_err_replace_valid[demod_id].reg_addr,
15073c4e0415SDaniel Scheller 			xpt_err_replace_valid[demod_id].lsb_pos,
15083c4e0415SDaniel Scheller 			xpt_err_replace_valid[demod_id].num_of_bits,
15093c4e0415SDaniel Scheller 			MXL_FALSE);
15103c4e0415SDaniel Scheller 		break;
15113c4e0415SDaniel Scheller 
15123c4e0415SDaniel Scheller 	case MXL_HYDRA_MPEG_ERR_REPLACE_VALID:
15133c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state,
15143c4e0415SDaniel Scheller 			xpt_err_replace_sync[demod_id].reg_addr,
15153c4e0415SDaniel Scheller 			xpt_err_replace_sync[demod_id].lsb_pos,
15163c4e0415SDaniel Scheller 			xpt_err_replace_sync[demod_id].num_of_bits,
15173c4e0415SDaniel Scheller 			MXL_FALSE);
15183c4e0415SDaniel Scheller 
15193c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state,
15203c4e0415SDaniel Scheller 			xpt_err_replace_valid[demod_id].reg_addr,
15213c4e0415SDaniel Scheller 			xpt_err_replace_valid[demod_id].lsb_pos,
15223c4e0415SDaniel Scheller 			xpt_err_replace_valid[demod_id].num_of_bits,
15233c4e0415SDaniel Scheller 			MXL_TRUE);
15243c4e0415SDaniel Scheller 		break;
15253c4e0415SDaniel Scheller 
15263c4e0415SDaniel Scheller 	case MXL_HYDRA_MPEG_ERR_INDICATION_DISABLED:
15273c4e0415SDaniel Scheller 	default:
15283c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state,
15293c4e0415SDaniel Scheller 			xpt_err_replace_sync[demod_id].reg_addr,
15303c4e0415SDaniel Scheller 			xpt_err_replace_sync[demod_id].lsb_pos,
15313c4e0415SDaniel Scheller 			xpt_err_replace_sync[demod_id].num_of_bits,
15323c4e0415SDaniel Scheller 			MXL_FALSE);
15333c4e0415SDaniel Scheller 
15343c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state,
15353c4e0415SDaniel Scheller 			xpt_err_replace_valid[demod_id].reg_addr,
15363c4e0415SDaniel Scheller 			xpt_err_replace_valid[demod_id].lsb_pos,
15373c4e0415SDaniel Scheller 			xpt_err_replace_valid[demod_id].num_of_bits,
15383c4e0415SDaniel Scheller 			MXL_FALSE);
15393c4e0415SDaniel Scheller 
15403c4e0415SDaniel Scheller 		break;
15413c4e0415SDaniel Scheller 
15423c4e0415SDaniel Scheller 	}
15433c4e0415SDaniel Scheller 
15443c4e0415SDaniel Scheller 	if (mpeg_out_param_ptr->mpeg_mode != MXL_HYDRA_MPEG_MODE_PARALLEL) {
15453c4e0415SDaniel Scheller 		status |= update_by_mnemonic(state,
15463c4e0415SDaniel Scheller 			xpt_enable_output[demod_id].reg_addr,
15473c4e0415SDaniel Scheller 			xpt_enable_output[demod_id].lsb_pos,
15483c4e0415SDaniel Scheller 			xpt_enable_output[demod_id].num_of_bits,
15493c4e0415SDaniel Scheller 			mpeg_out_param_ptr->enable);
15503c4e0415SDaniel Scheller 	}
15513c4e0415SDaniel Scheller 	return status;
15523c4e0415SDaniel Scheller }
15533c4e0415SDaniel Scheller 
15543c4e0415SDaniel Scheller static int config_mux(struct mxl *state)
15553c4e0415SDaniel Scheller {
15563c4e0415SDaniel Scheller 	update_by_mnemonic(state, 0x9070000C, 0, 1, 0);
15573c4e0415SDaniel Scheller 	update_by_mnemonic(state, 0x9070000C, 1, 1, 0);
15583c4e0415SDaniel Scheller 	update_by_mnemonic(state, 0x9070000C, 2, 1, 0);
15593c4e0415SDaniel Scheller 	update_by_mnemonic(state, 0x9070000C, 3, 1, 0);
15603c4e0415SDaniel Scheller 	update_by_mnemonic(state, 0x9070000C, 4, 1, 0);
15613c4e0415SDaniel Scheller 	update_by_mnemonic(state, 0x9070000C, 5, 1, 0);
15623c4e0415SDaniel Scheller 	update_by_mnemonic(state, 0x9070000C, 6, 1, 0);
15633c4e0415SDaniel Scheller 	update_by_mnemonic(state, 0x9070000C, 7, 1, 0);
15643c4e0415SDaniel Scheller 	update_by_mnemonic(state, 0x90700008, 0, 2, 1);
15653c4e0415SDaniel Scheller 	update_by_mnemonic(state, 0x90700008, 2, 2, 1);
15663c4e0415SDaniel Scheller 	return 0;
15673c4e0415SDaniel Scheller }
15683c4e0415SDaniel Scheller 
15693c4e0415SDaniel Scheller static int load_fw(struct mxl *state, struct mxl5xx_cfg *cfg)
15703c4e0415SDaniel Scheller {
15713c4e0415SDaniel Scheller 	int stat = 0;
15723c4e0415SDaniel Scheller 	u8 *buf;
15733c4e0415SDaniel Scheller 
15743c4e0415SDaniel Scheller 	if (cfg->fw)
15753c4e0415SDaniel Scheller 		return firmware_download(state, cfg->fw, cfg->fw_len);
15763c4e0415SDaniel Scheller 
15773c4e0415SDaniel Scheller 	if (!cfg->fw_read)
15783c4e0415SDaniel Scheller 		return -1;
15793c4e0415SDaniel Scheller 
15803c4e0415SDaniel Scheller 	buf = vmalloc(0x40000);
15813c4e0415SDaniel Scheller 	if (!buf)
15823c4e0415SDaniel Scheller 		return -ENOMEM;
15833c4e0415SDaniel Scheller 
15843c4e0415SDaniel Scheller 	cfg->fw_read(cfg->fw_priv, buf, 0x40000);
15853c4e0415SDaniel Scheller 	stat = firmware_download(state, buf, 0x40000);
15863c4e0415SDaniel Scheller 	vfree(buf);
15873c4e0415SDaniel Scheller 
15883c4e0415SDaniel Scheller 	return stat;
15893c4e0415SDaniel Scheller }
15903c4e0415SDaniel Scheller 
15913c4e0415SDaniel Scheller static int validate_sku(struct mxl *state)
15923c4e0415SDaniel Scheller {
15933c4e0415SDaniel Scheller 	u32 pad_mux_bond = 0, prcm_chip_id = 0, prcm_so_cid = 0;
15943c4e0415SDaniel Scheller 	int status;
15953c4e0415SDaniel Scheller 	u32 type = state->base->type;
15963c4e0415SDaniel Scheller 
15973c4e0415SDaniel Scheller 	status = read_by_mnemonic(state, 0x90000190, 0, 3, &pad_mux_bond);
15983c4e0415SDaniel Scheller 	status |= read_by_mnemonic(state, 0x80030000, 0, 12, &prcm_chip_id);
15993c4e0415SDaniel Scheller 	status |= read_by_mnemonic(state, 0x80030004, 24, 8, &prcm_so_cid);
16003c4e0415SDaniel Scheller 	if (status)
16013c4e0415SDaniel Scheller 		return -1;
16023c4e0415SDaniel Scheller 
16033c4e0415SDaniel Scheller 	dev_info(state->i2cdev, "padMuxBond=%08x, prcmChipId=%08x, prcmSoCId=%08x\n",
16043c4e0415SDaniel Scheller 		pad_mux_bond, prcm_chip_id, prcm_so_cid);
16053c4e0415SDaniel Scheller 
16063c4e0415SDaniel Scheller 	if (prcm_chip_id != 0x560) {
16073c4e0415SDaniel Scheller 		switch (pad_mux_bond) {
16083c4e0415SDaniel Scheller 		case MXL_HYDRA_SKU_ID_581:
16093c4e0415SDaniel Scheller 			if (type == MXL_HYDRA_DEVICE_581)
16103c4e0415SDaniel Scheller 				return 0;
16113c4e0415SDaniel Scheller 			if (type == MXL_HYDRA_DEVICE_581S) {
16123c4e0415SDaniel Scheller 				state->base->type = MXL_HYDRA_DEVICE_581;
16133c4e0415SDaniel Scheller 				return 0;
16143c4e0415SDaniel Scheller 			}
16153c4e0415SDaniel Scheller 			break;
16163c4e0415SDaniel Scheller 		case MXL_HYDRA_SKU_ID_584:
16173c4e0415SDaniel Scheller 			if (type == MXL_HYDRA_DEVICE_584)
16183c4e0415SDaniel Scheller 				return 0;
16193c4e0415SDaniel Scheller 			break;
16203c4e0415SDaniel Scheller 		case MXL_HYDRA_SKU_ID_544:
16213c4e0415SDaniel Scheller 			if (type == MXL_HYDRA_DEVICE_544)
16223c4e0415SDaniel Scheller 				return 0;
16233c4e0415SDaniel Scheller 			if (type == MXL_HYDRA_DEVICE_542)
16243c4e0415SDaniel Scheller 				return 0;
16253c4e0415SDaniel Scheller 			break;
16263c4e0415SDaniel Scheller 		case MXL_HYDRA_SKU_ID_582:
16273c4e0415SDaniel Scheller 			if (type == MXL_HYDRA_DEVICE_582)
16283c4e0415SDaniel Scheller 				return 0;
16293c4e0415SDaniel Scheller 			break;
16303c4e0415SDaniel Scheller 		default:
16313c4e0415SDaniel Scheller 			return -1;
16323c4e0415SDaniel Scheller 		}
16333c4e0415SDaniel Scheller 	} else {
16343c4e0415SDaniel Scheller 
16353c4e0415SDaniel Scheller 	}
16363c4e0415SDaniel Scheller 	return -1;
16373c4e0415SDaniel Scheller }
16383c4e0415SDaniel Scheller 
16393c4e0415SDaniel Scheller static int get_fwinfo(struct mxl *state)
16403c4e0415SDaniel Scheller {
16413c4e0415SDaniel Scheller 	int status;
16423c4e0415SDaniel Scheller 	u32 val = 0;
16433c4e0415SDaniel Scheller 
16443c4e0415SDaniel Scheller 	status = read_by_mnemonic(state, 0x90000190, 0, 3, &val);
16453c4e0415SDaniel Scheller 	if (status)
16463c4e0415SDaniel Scheller 		return status;
16473c4e0415SDaniel Scheller 	dev_info(state->i2cdev, "chipID=%08x\n", val);
16483c4e0415SDaniel Scheller 
16493c4e0415SDaniel Scheller 	status = read_by_mnemonic(state, 0x80030004, 8, 8, &val);
16503c4e0415SDaniel Scheller 	if (status)
16513c4e0415SDaniel Scheller 		return status;
16523c4e0415SDaniel Scheller 	dev_info(state->i2cdev, "chipVer=%08x\n", val);
16533c4e0415SDaniel Scheller 
16543c4e0415SDaniel Scheller 	status = read_register(state, HYDRA_FIRMWARE_VERSION, &val);
16553c4e0415SDaniel Scheller 	if (status)
16563c4e0415SDaniel Scheller 		return status;
16573c4e0415SDaniel Scheller 	dev_info(state->i2cdev, "FWVer=%08x\n", val);
16583c4e0415SDaniel Scheller 
16593c4e0415SDaniel Scheller 	state->base->fwversion = val;
16603c4e0415SDaniel Scheller 	return status;
16613c4e0415SDaniel Scheller }
16623c4e0415SDaniel Scheller 
16633c4e0415SDaniel Scheller 
16643c4e0415SDaniel Scheller static u8 ts_map1_to_1[MXL_HYDRA_DEMOD_MAX] = {
16653c4e0415SDaniel Scheller 	MXL_HYDRA_DEMOD_ID_0,
16663c4e0415SDaniel Scheller 	MXL_HYDRA_DEMOD_ID_1,
16673c4e0415SDaniel Scheller 	MXL_HYDRA_DEMOD_ID_2,
16683c4e0415SDaniel Scheller 	MXL_HYDRA_DEMOD_ID_3,
16693c4e0415SDaniel Scheller 	MXL_HYDRA_DEMOD_ID_4,
16703c4e0415SDaniel Scheller 	MXL_HYDRA_DEMOD_ID_5,
16713c4e0415SDaniel Scheller 	MXL_HYDRA_DEMOD_ID_6,
16723c4e0415SDaniel Scheller 	MXL_HYDRA_DEMOD_ID_7,
16733c4e0415SDaniel Scheller };
16743c4e0415SDaniel Scheller 
16753c4e0415SDaniel Scheller static u8 ts_map54x[MXL_HYDRA_DEMOD_MAX] = {
16763c4e0415SDaniel Scheller 	MXL_HYDRA_DEMOD_ID_2,
16773c4e0415SDaniel Scheller 	MXL_HYDRA_DEMOD_ID_3,
16783c4e0415SDaniel Scheller 	MXL_HYDRA_DEMOD_ID_4,
16793c4e0415SDaniel Scheller 	MXL_HYDRA_DEMOD_ID_5,
16803c4e0415SDaniel Scheller 	MXL_HYDRA_DEMOD_MAX,
16813c4e0415SDaniel Scheller 	MXL_HYDRA_DEMOD_MAX,
16823c4e0415SDaniel Scheller 	MXL_HYDRA_DEMOD_MAX,
16833c4e0415SDaniel Scheller 	MXL_HYDRA_DEMOD_MAX,
16843c4e0415SDaniel Scheller };
16853c4e0415SDaniel Scheller 
16863c4e0415SDaniel Scheller static int probe(struct mxl *state, struct mxl5xx_cfg *cfg)
16873c4e0415SDaniel Scheller {
16883c4e0415SDaniel Scheller 	u32 chipver;
16893c4e0415SDaniel Scheller 	int fw, status, j;
16903c4e0415SDaniel Scheller 	struct MXL_HYDRA_MPEGOUT_PARAM_T mpeg_interface_cfg;
16913c4e0415SDaniel Scheller 
16923c4e0415SDaniel Scheller 	state->base->ts_map = ts_map1_to_1;
16933c4e0415SDaniel Scheller 
16943c4e0415SDaniel Scheller 	switch (state->base->type) {
16953c4e0415SDaniel Scheller 	case MXL_HYDRA_DEVICE_581:
16963c4e0415SDaniel Scheller 	case MXL_HYDRA_DEVICE_581S:
16973c4e0415SDaniel Scheller 		state->base->can_clkout = 1;
16983c4e0415SDaniel Scheller 		state->base->demod_num = 8;
16993c4e0415SDaniel Scheller 		state->base->tuner_num = 1;
17003c4e0415SDaniel Scheller 		state->base->sku_type = MXL_HYDRA_SKU_TYPE_581;
17013c4e0415SDaniel Scheller 		break;
17023c4e0415SDaniel Scheller 	case MXL_HYDRA_DEVICE_582:
17033c4e0415SDaniel Scheller 		state->base->can_clkout = 1;
17043c4e0415SDaniel Scheller 		state->base->demod_num = 8;
17053c4e0415SDaniel Scheller 		state->base->tuner_num = 3;
17063c4e0415SDaniel Scheller 		state->base->sku_type = MXL_HYDRA_SKU_TYPE_582;
17073c4e0415SDaniel Scheller 		break;
17083c4e0415SDaniel Scheller 	case MXL_HYDRA_DEVICE_585:
17093c4e0415SDaniel Scheller 		state->base->can_clkout = 0;
17103c4e0415SDaniel Scheller 		state->base->demod_num = 8;
17113c4e0415SDaniel Scheller 		state->base->tuner_num = 4;
17123c4e0415SDaniel Scheller 		state->base->sku_type = MXL_HYDRA_SKU_TYPE_585;
17133c4e0415SDaniel Scheller 		break;
17143c4e0415SDaniel Scheller 	case MXL_HYDRA_DEVICE_544:
17153c4e0415SDaniel Scheller 		state->base->can_clkout = 0;
17163c4e0415SDaniel Scheller 		state->base->demod_num = 4;
17173c4e0415SDaniel Scheller 		state->base->tuner_num = 4;
17183c4e0415SDaniel Scheller 		state->base->sku_type = MXL_HYDRA_SKU_TYPE_544;
17193c4e0415SDaniel Scheller 		state->base->ts_map = ts_map54x;
17203c4e0415SDaniel Scheller 		break;
17213c4e0415SDaniel Scheller 	case MXL_HYDRA_DEVICE_541:
17223c4e0415SDaniel Scheller 	case MXL_HYDRA_DEVICE_541S:
17233c4e0415SDaniel Scheller 		state->base->can_clkout = 0;
17243c4e0415SDaniel Scheller 		state->base->demod_num = 4;
17253c4e0415SDaniel Scheller 		state->base->tuner_num = 1;
17263c4e0415SDaniel Scheller 		state->base->sku_type = MXL_HYDRA_SKU_TYPE_541;
17273c4e0415SDaniel Scheller 		state->base->ts_map = ts_map54x;
17283c4e0415SDaniel Scheller 		break;
17293c4e0415SDaniel Scheller 	case MXL_HYDRA_DEVICE_561:
17303c4e0415SDaniel Scheller 	case MXL_HYDRA_DEVICE_561S:
17313c4e0415SDaniel Scheller 		state->base->can_clkout = 0;
17323c4e0415SDaniel Scheller 		state->base->demod_num = 6;
17333c4e0415SDaniel Scheller 		state->base->tuner_num = 1;
17343c4e0415SDaniel Scheller 		state->base->sku_type = MXL_HYDRA_SKU_TYPE_561;
17353c4e0415SDaniel Scheller 		break;
17363c4e0415SDaniel Scheller 	case MXL_HYDRA_DEVICE_568:
17373c4e0415SDaniel Scheller 		state->base->can_clkout = 0;
17383c4e0415SDaniel Scheller 		state->base->demod_num = 8;
17393c4e0415SDaniel Scheller 		state->base->tuner_num = 1;
17403c4e0415SDaniel Scheller 		state->base->chan_bond = 1;
17413c4e0415SDaniel Scheller 		state->base->sku_type = MXL_HYDRA_SKU_TYPE_568;
17423c4e0415SDaniel Scheller 		break;
17433c4e0415SDaniel Scheller 	case MXL_HYDRA_DEVICE_542:
17443c4e0415SDaniel Scheller 		state->base->can_clkout = 1;
17453c4e0415SDaniel Scheller 		state->base->demod_num = 4;
17463c4e0415SDaniel Scheller 		state->base->tuner_num = 3;
17473c4e0415SDaniel Scheller 		state->base->sku_type = MXL_HYDRA_SKU_TYPE_542;
17483c4e0415SDaniel Scheller 		state->base->ts_map = ts_map54x;
17493c4e0415SDaniel Scheller 		break;
17503c4e0415SDaniel Scheller 	case MXL_HYDRA_DEVICE_TEST:
17513c4e0415SDaniel Scheller 	case MXL_HYDRA_DEVICE_584:
17523c4e0415SDaniel Scheller 	default:
17533c4e0415SDaniel Scheller 		state->base->can_clkout = 0;
17543c4e0415SDaniel Scheller 		state->base->demod_num = 8;
17553c4e0415SDaniel Scheller 		state->base->tuner_num = 4;
17563c4e0415SDaniel Scheller 		state->base->sku_type = MXL_HYDRA_SKU_TYPE_584;
17573c4e0415SDaniel Scheller 		break;
17583c4e0415SDaniel Scheller 	}
17593c4e0415SDaniel Scheller 
17603c4e0415SDaniel Scheller 	status = validate_sku(state);
17613c4e0415SDaniel Scheller 	if (status)
17623c4e0415SDaniel Scheller 		return status;
17633c4e0415SDaniel Scheller 
17643c4e0415SDaniel Scheller 	update_by_mnemonic(state, 0x80030014, 9, 1, 1);
17653c4e0415SDaniel Scheller 	update_by_mnemonic(state, 0x8003003C, 12, 1, 1);
17663c4e0415SDaniel Scheller 	status = read_by_mnemonic(state, 0x80030000, 12, 4, &chipver);
17673c4e0415SDaniel Scheller 	if (status)
17683c4e0415SDaniel Scheller 		state->base->chipversion = 0;
17693c4e0415SDaniel Scheller 	else
17703c4e0415SDaniel Scheller 		state->base->chipversion = (chipver == 2) ? 2 : 1;
17713c4e0415SDaniel Scheller 	dev_info(state->i2cdev, "Hydra chip version %u\n",
17723c4e0415SDaniel Scheller 		state->base->chipversion);
17733c4e0415SDaniel Scheller 
17743c4e0415SDaniel Scheller 	cfg_dev_xtal(state, cfg->clk, cfg->cap, 0);
17753c4e0415SDaniel Scheller 
17763c4e0415SDaniel Scheller 	fw = firmware_is_alive(state);
17773c4e0415SDaniel Scheller 	if (!fw) {
17783c4e0415SDaniel Scheller 		status = load_fw(state, cfg);
17793c4e0415SDaniel Scheller 		if (status)
17803c4e0415SDaniel Scheller 			return status;
17813c4e0415SDaniel Scheller 	}
17823c4e0415SDaniel Scheller 	get_fwinfo(state);
17833c4e0415SDaniel Scheller 
17843c4e0415SDaniel Scheller 	config_mux(state);
17853c4e0415SDaniel Scheller 	mpeg_interface_cfg.enable = MXL_ENABLE;
17863c4e0415SDaniel Scheller 	mpeg_interface_cfg.lsb_or_msb_first = MXL_HYDRA_MPEG_SERIAL_MSB_1ST;
17873c4e0415SDaniel Scheller 	/*  supports only (0-104&139)MHz */
17883c4e0415SDaniel Scheller 	if (cfg->ts_clk)
17893c4e0415SDaniel Scheller 		mpeg_interface_cfg.max_mpeg_clk_rate = cfg->ts_clk;
17903c4e0415SDaniel Scheller 	else
17913c4e0415SDaniel Scheller 		mpeg_interface_cfg.max_mpeg_clk_rate = 69; /* 139; */
17923c4e0415SDaniel Scheller 	mpeg_interface_cfg.mpeg_clk_phase = MXL_HYDRA_MPEG_CLK_PHASE_SHIFT_0_DEG;
17933c4e0415SDaniel Scheller 	mpeg_interface_cfg.mpeg_clk_pol = MXL_HYDRA_MPEG_CLK_IN_PHASE;
17943c4e0415SDaniel Scheller 	/* MXL_HYDRA_MPEG_CLK_GAPPED; */
17953c4e0415SDaniel Scheller 	mpeg_interface_cfg.mpeg_clk_type = MXL_HYDRA_MPEG_CLK_CONTINUOUS;
17963c4e0415SDaniel Scheller 	mpeg_interface_cfg.mpeg_error_indication =
17973c4e0415SDaniel Scheller 		MXL_HYDRA_MPEG_ERR_INDICATION_DISABLED;
17983c4e0415SDaniel Scheller 	mpeg_interface_cfg.mpeg_mode = MXL_HYDRA_MPEG_MODE_SERIAL_3_WIRE;
17993c4e0415SDaniel Scheller 	mpeg_interface_cfg.mpeg_sync_pol  = MXL_HYDRA_MPEG_ACTIVE_HIGH;
18003c4e0415SDaniel Scheller 	mpeg_interface_cfg.mpeg_sync_pulse_width  = MXL_HYDRA_MPEG_SYNC_WIDTH_BIT;
18013c4e0415SDaniel Scheller 	mpeg_interface_cfg.mpeg_valid_pol  = MXL_HYDRA_MPEG_ACTIVE_HIGH;
18023c4e0415SDaniel Scheller 
18033c4e0415SDaniel Scheller 	for (j = 0; j < state->base->demod_num; j++) {
18043c4e0415SDaniel Scheller 		status = config_ts(state, (enum MXL_HYDRA_DEMOD_ID_E) j,
18053c4e0415SDaniel Scheller 				   &mpeg_interface_cfg);
18063c4e0415SDaniel Scheller 		if (status)
18073c4e0415SDaniel Scheller 			return status;
18083c4e0415SDaniel Scheller 	}
18093c4e0415SDaniel Scheller 	set_drive_strength(state, 1);
18103c4e0415SDaniel Scheller 	return 0;
18113c4e0415SDaniel Scheller }
18123c4e0415SDaniel Scheller 
18133c4e0415SDaniel Scheller struct dvb_frontend *mxl5xx_attach(struct i2c_adapter *i2c,
18143c4e0415SDaniel Scheller 	struct mxl5xx_cfg *cfg, u32 demod, u32 tuner,
18153c4e0415SDaniel Scheller 	int (**fn_set_input)(struct dvb_frontend *, int))
18163c4e0415SDaniel Scheller {
18173c4e0415SDaniel Scheller 	struct mxl *state;
18183c4e0415SDaniel Scheller 	struct mxl_base *base;
18193c4e0415SDaniel Scheller 
18203c4e0415SDaniel Scheller 	state = kzalloc(sizeof(struct mxl), GFP_KERNEL);
18213c4e0415SDaniel Scheller 	if (!state)
18223c4e0415SDaniel Scheller 		return NULL;
18233c4e0415SDaniel Scheller 
18243c4e0415SDaniel Scheller 	state->demod = demod;
18253c4e0415SDaniel Scheller 	state->tuner = tuner;
18263c4e0415SDaniel Scheller 	state->tuner_in_use = 0xffffffff;
18273c4e0415SDaniel Scheller 	state->i2cdev = &i2c->dev;
18283c4e0415SDaniel Scheller 
18293c4e0415SDaniel Scheller 	base = match_base(i2c, cfg->adr);
18303c4e0415SDaniel Scheller 	if (base) {
18313c4e0415SDaniel Scheller 		base->count++;
18323c4e0415SDaniel Scheller 		if (base->count > base->demod_num)
18333c4e0415SDaniel Scheller 			goto fail;
18343c4e0415SDaniel Scheller 		state->base = base;
18353c4e0415SDaniel Scheller 	} else {
18363c4e0415SDaniel Scheller 		base = kzalloc(sizeof(struct mxl_base), GFP_KERNEL);
18373c4e0415SDaniel Scheller 		if (!base)
18383c4e0415SDaniel Scheller 			goto fail;
18393c4e0415SDaniel Scheller 		base->i2c = i2c;
18403c4e0415SDaniel Scheller 		base->adr = cfg->adr;
18413c4e0415SDaniel Scheller 		base->type = cfg->type;
18423c4e0415SDaniel Scheller 		base->count = 1;
18433c4e0415SDaniel Scheller 		mutex_init(&base->i2c_lock);
18443c4e0415SDaniel Scheller 		mutex_init(&base->status_lock);
18453c4e0415SDaniel Scheller 		mutex_init(&base->tune_lock);
18463c4e0415SDaniel Scheller 		INIT_LIST_HEAD(&base->mxls);
18473c4e0415SDaniel Scheller 
18483c4e0415SDaniel Scheller 		state->base = base;
18493c4e0415SDaniel Scheller 		if (probe(state, cfg) < 0) {
18503c4e0415SDaniel Scheller 			kfree(base);
18513c4e0415SDaniel Scheller 			goto fail;
18523c4e0415SDaniel Scheller 		}
18533c4e0415SDaniel Scheller 		list_add(&base->mxllist, &mxllist);
18543c4e0415SDaniel Scheller 	}
18553c4e0415SDaniel Scheller 	state->fe.ops               = mxl_ops;
18563c4e0415SDaniel Scheller 	state->xbar[0]              = 4;
18573c4e0415SDaniel Scheller 	state->xbar[1]              = demod;
18583c4e0415SDaniel Scheller 	state->xbar[2]              = 8;
18593c4e0415SDaniel Scheller 	state->fe.demodulator_priv  = state;
18603c4e0415SDaniel Scheller 	*fn_set_input               = set_input;
18613c4e0415SDaniel Scheller 
18623c4e0415SDaniel Scheller 	list_add(&state->mxl, &base->mxls);
18633c4e0415SDaniel Scheller 	return &state->fe;
18643c4e0415SDaniel Scheller 
18653c4e0415SDaniel Scheller fail:
18663c4e0415SDaniel Scheller 	kfree(state);
18673c4e0415SDaniel Scheller 	return NULL;
18683c4e0415SDaniel Scheller }
18693c4e0415SDaniel Scheller EXPORT_SYMBOL_GPL(mxl5xx_attach);
18703c4e0415SDaniel Scheller 
18713c4e0415SDaniel Scheller MODULE_DESCRIPTION("MaxLinear MxL5xx DVB-S/S2 tuner-demodulator driver");
18723c4e0415SDaniel Scheller MODULE_AUTHOR("Ralph and Marcus Metzler, Metzler Brothers Systementwicklung GbR");
18733c4e0415SDaniel Scheller MODULE_LICENSE("GPL");
1874