xref: /OK3568_Linux_fs/kernel/drivers/media/pci/ddbridge/ddbridge-max.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * ddbridge-max.c: Digital Devices bridge MAX card support
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2010-2017 Digital Devices GmbH
6*4882a593Smuzhiyun  *                         Ralph Metzler <rjkm@metzlerbros.de>
7*4882a593Smuzhiyun  *                         Marcus Metzler <mocm@metzlerbros.de>
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * This program is free software; you can redistribute it and/or
10*4882a593Smuzhiyun  * modify it under the terms of the GNU General Public License
11*4882a593Smuzhiyun  * version 2 only, as published by the Free Software Foundation.
12*4882a593Smuzhiyun  *
13*4882a593Smuzhiyun  * This program is distributed in the hope that it will be useful,
14*4882a593Smuzhiyun  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15*4882a593Smuzhiyun  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16*4882a593Smuzhiyun  * GNU General Public License for more details.
17*4882a593Smuzhiyun  */
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #include <linux/module.h>
20*4882a593Smuzhiyun #include <linux/init.h>
21*4882a593Smuzhiyun #include <linux/interrupt.h>
22*4882a593Smuzhiyun #include <linux/delay.h>
23*4882a593Smuzhiyun #include <linux/slab.h>
24*4882a593Smuzhiyun #include <linux/poll.h>
25*4882a593Smuzhiyun #include <linux/io.h>
26*4882a593Smuzhiyun #include <linux/pci.h>
27*4882a593Smuzhiyun #include <linux/pci_ids.h>
28*4882a593Smuzhiyun #include <linux/timer.h>
29*4882a593Smuzhiyun #include <linux/i2c.h>
30*4882a593Smuzhiyun #include <linux/swab.h>
31*4882a593Smuzhiyun #include <linux/vmalloc.h>
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun #include "ddbridge.h"
34*4882a593Smuzhiyun #include "ddbridge-regs.h"
35*4882a593Smuzhiyun #include "ddbridge-io.h"
36*4882a593Smuzhiyun #include "ddbridge-mci.h"
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun #include "ddbridge-max.h"
39*4882a593Smuzhiyun #include "mxl5xx.h"
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun /******************************************************************************/
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun /* MaxS4/8 related modparams */
44*4882a593Smuzhiyun static int fmode;
45*4882a593Smuzhiyun module_param(fmode, int, 0444);
46*4882a593Smuzhiyun MODULE_PARM_DESC(fmode, "frontend emulation mode");
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun static int fmode_sat = -1;
49*4882a593Smuzhiyun module_param(fmode_sat, int, 0444);
50*4882a593Smuzhiyun MODULE_PARM_DESC(fmode_sat, "set frontend emulation mode sat");
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun static int old_quattro;
53*4882a593Smuzhiyun module_param(old_quattro, int, 0444);
54*4882a593Smuzhiyun MODULE_PARM_DESC(old_quattro, "old quattro LNB input order ");
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun /******************************************************************************/
57*4882a593Smuzhiyun 
lnb_command(struct ddb * dev,u32 link,u32 lnb,u32 cmd)58*4882a593Smuzhiyun static int lnb_command(struct ddb *dev, u32 link, u32 lnb, u32 cmd)
59*4882a593Smuzhiyun {
60*4882a593Smuzhiyun 	u32 c, v = 0, tag = DDB_LINK_TAG(link);
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	v = LNB_TONE & (dev->link[link].lnb.tone << (15 - lnb));
63*4882a593Smuzhiyun 	ddbwritel(dev, cmd | v, tag | LNB_CONTROL(lnb));
64*4882a593Smuzhiyun 	for (c = 0; c < 10; c++) {
65*4882a593Smuzhiyun 		v = ddbreadl(dev, tag | LNB_CONTROL(lnb));
66*4882a593Smuzhiyun 		if ((v & LNB_BUSY) == 0)
67*4882a593Smuzhiyun 			break;
68*4882a593Smuzhiyun 		msleep(20);
69*4882a593Smuzhiyun 	}
70*4882a593Smuzhiyun 	if (c == 10)
71*4882a593Smuzhiyun 		dev_info(dev->dev, "%s lnb = %08x  cmd = %08x\n",
72*4882a593Smuzhiyun 			 __func__, lnb, cmd);
73*4882a593Smuzhiyun 	return 0;
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun 
max_send_master_cmd(struct dvb_frontend * fe,struct dvb_diseqc_master_cmd * cmd)76*4882a593Smuzhiyun static int max_send_master_cmd(struct dvb_frontend *fe,
77*4882a593Smuzhiyun 			       struct dvb_diseqc_master_cmd *cmd)
78*4882a593Smuzhiyun {
79*4882a593Smuzhiyun 	struct ddb_input *input = fe->sec_priv;
80*4882a593Smuzhiyun 	struct ddb_port *port = input->port;
81*4882a593Smuzhiyun 	struct ddb *dev = port->dev;
82*4882a593Smuzhiyun 	struct ddb_dvb *dvb = &port->dvb[input->nr & 1];
83*4882a593Smuzhiyun 	u32 tag = DDB_LINK_TAG(port->lnr);
84*4882a593Smuzhiyun 	int i;
85*4882a593Smuzhiyun 	u32 fmode = dev->link[port->lnr].lnb.fmode;
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	if (fmode == 2 || fmode == 1)
88*4882a593Smuzhiyun 		return 0;
89*4882a593Smuzhiyun 	if (dvb->diseqc_send_master_cmd)
90*4882a593Smuzhiyun 		dvb->diseqc_send_master_cmd(fe, cmd);
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 	mutex_lock(&dev->link[port->lnr].lnb.lock);
93*4882a593Smuzhiyun 	ddbwritel(dev, 0, tag | LNB_BUF_LEVEL(dvb->input));
94*4882a593Smuzhiyun 	for (i = 0; i < cmd->msg_len; i++)
95*4882a593Smuzhiyun 		ddbwritel(dev, cmd->msg[i], tag | LNB_BUF_WRITE(dvb->input));
96*4882a593Smuzhiyun 	lnb_command(dev, port->lnr, dvb->input, LNB_CMD_DISEQC);
97*4882a593Smuzhiyun 	mutex_unlock(&dev->link[port->lnr].lnb.lock);
98*4882a593Smuzhiyun 	return 0;
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun 
lnb_send_diseqc(struct ddb * dev,u32 link,u32 input,struct dvb_diseqc_master_cmd * cmd)101*4882a593Smuzhiyun static int lnb_send_diseqc(struct ddb *dev, u32 link, u32 input,
102*4882a593Smuzhiyun 			   struct dvb_diseqc_master_cmd *cmd)
103*4882a593Smuzhiyun {
104*4882a593Smuzhiyun 	u32 tag = DDB_LINK_TAG(link);
105*4882a593Smuzhiyun 	int i;
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	ddbwritel(dev, 0, tag | LNB_BUF_LEVEL(input));
108*4882a593Smuzhiyun 	for (i = 0; i < cmd->msg_len; i++)
109*4882a593Smuzhiyun 		ddbwritel(dev, cmd->msg[i], tag | LNB_BUF_WRITE(input));
110*4882a593Smuzhiyun 	lnb_command(dev, link, input, LNB_CMD_DISEQC);
111*4882a593Smuzhiyun 	return 0;
112*4882a593Smuzhiyun }
113*4882a593Smuzhiyun 
lnb_set_sat(struct ddb * dev,u32 link,u32 input,u32 sat,u32 band,u32 hor)114*4882a593Smuzhiyun static int lnb_set_sat(struct ddb *dev, u32 link, u32 input, u32 sat, u32 band,
115*4882a593Smuzhiyun 		       u32 hor)
116*4882a593Smuzhiyun {
117*4882a593Smuzhiyun 	struct dvb_diseqc_master_cmd cmd = {
118*4882a593Smuzhiyun 		.msg = {0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00},
119*4882a593Smuzhiyun 		.msg_len = 4
120*4882a593Smuzhiyun 	};
121*4882a593Smuzhiyun 	cmd.msg[3] = 0xf0 | (((sat << 2) & 0x0c) | (band ? 1 : 0) |
122*4882a593Smuzhiyun 		(hor ? 2 : 0));
123*4882a593Smuzhiyun 	return lnb_send_diseqc(dev, link, input, &cmd);
124*4882a593Smuzhiyun }
125*4882a593Smuzhiyun 
lnb_set_tone(struct ddb * dev,u32 link,u32 input,enum fe_sec_tone_mode tone)126*4882a593Smuzhiyun static int lnb_set_tone(struct ddb *dev, u32 link, u32 input,
127*4882a593Smuzhiyun 			enum fe_sec_tone_mode tone)
128*4882a593Smuzhiyun {
129*4882a593Smuzhiyun 	int s = 0;
130*4882a593Smuzhiyun 	u32 mask = (1ULL << input);
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	switch (tone) {
133*4882a593Smuzhiyun 	case SEC_TONE_OFF:
134*4882a593Smuzhiyun 		if (!(dev->link[link].lnb.tone & mask))
135*4882a593Smuzhiyun 			return 0;
136*4882a593Smuzhiyun 		dev->link[link].lnb.tone &= ~(1ULL << input);
137*4882a593Smuzhiyun 		break;
138*4882a593Smuzhiyun 	case SEC_TONE_ON:
139*4882a593Smuzhiyun 		if (dev->link[link].lnb.tone & mask)
140*4882a593Smuzhiyun 			return 0;
141*4882a593Smuzhiyun 		dev->link[link].lnb.tone |= (1ULL << input);
142*4882a593Smuzhiyun 		break;
143*4882a593Smuzhiyun 	default:
144*4882a593Smuzhiyun 		s = -EINVAL;
145*4882a593Smuzhiyun 		break;
146*4882a593Smuzhiyun 	}
147*4882a593Smuzhiyun 	if (!s)
148*4882a593Smuzhiyun 		s = lnb_command(dev, link, input, LNB_CMD_NOP);
149*4882a593Smuzhiyun 	return s;
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun 
lnb_set_voltage(struct ddb * dev,u32 link,u32 input,enum fe_sec_voltage voltage)152*4882a593Smuzhiyun static int lnb_set_voltage(struct ddb *dev, u32 link, u32 input,
153*4882a593Smuzhiyun 			   enum fe_sec_voltage voltage)
154*4882a593Smuzhiyun {
155*4882a593Smuzhiyun 	int s = 0;
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	if (dev->link[link].lnb.oldvoltage[input] == voltage)
158*4882a593Smuzhiyun 		return 0;
159*4882a593Smuzhiyun 	switch (voltage) {
160*4882a593Smuzhiyun 	case SEC_VOLTAGE_OFF:
161*4882a593Smuzhiyun 		if (dev->link[link].lnb.voltage[input])
162*4882a593Smuzhiyun 			return 0;
163*4882a593Smuzhiyun 		lnb_command(dev, link, input, LNB_CMD_OFF);
164*4882a593Smuzhiyun 		break;
165*4882a593Smuzhiyun 	case SEC_VOLTAGE_13:
166*4882a593Smuzhiyun 		lnb_command(dev, link, input, LNB_CMD_LOW);
167*4882a593Smuzhiyun 		break;
168*4882a593Smuzhiyun 	case SEC_VOLTAGE_18:
169*4882a593Smuzhiyun 		lnb_command(dev, link, input, LNB_CMD_HIGH);
170*4882a593Smuzhiyun 		break;
171*4882a593Smuzhiyun 	default:
172*4882a593Smuzhiyun 		s = -EINVAL;
173*4882a593Smuzhiyun 		break;
174*4882a593Smuzhiyun 	}
175*4882a593Smuzhiyun 	dev->link[link].lnb.oldvoltage[input] = voltage;
176*4882a593Smuzhiyun 	return s;
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun 
max_set_input_unlocked(struct dvb_frontend * fe,int in)179*4882a593Smuzhiyun static int max_set_input_unlocked(struct dvb_frontend *fe, int in)
180*4882a593Smuzhiyun {
181*4882a593Smuzhiyun 	struct ddb_input *input = fe->sec_priv;
182*4882a593Smuzhiyun 	struct ddb_port *port = input->port;
183*4882a593Smuzhiyun 	struct ddb *dev = port->dev;
184*4882a593Smuzhiyun 	struct ddb_dvb *dvb = &port->dvb[input->nr & 1];
185*4882a593Smuzhiyun 	int res = 0;
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	if (in > 3)
188*4882a593Smuzhiyun 		return -EINVAL;
189*4882a593Smuzhiyun 	if (dvb->input != in) {
190*4882a593Smuzhiyun 		u32 bit = (1ULL << input->nr);
191*4882a593Smuzhiyun 		u32 obit =
192*4882a593Smuzhiyun 			dev->link[port->lnr].lnb.voltage[dvb->input & 3] & bit;
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 		dev->link[port->lnr].lnb.voltage[dvb->input & 3] &= ~bit;
195*4882a593Smuzhiyun 		dvb->input = in;
196*4882a593Smuzhiyun 		dev->link[port->lnr].lnb.voltage[dvb->input & 3] |= obit;
197*4882a593Smuzhiyun 	}
198*4882a593Smuzhiyun 	res = dvb->set_input(fe, in);
199*4882a593Smuzhiyun 	return res;
200*4882a593Smuzhiyun }
201*4882a593Smuzhiyun 
max_set_tone(struct dvb_frontend * fe,enum fe_sec_tone_mode tone)202*4882a593Smuzhiyun static int max_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone)
203*4882a593Smuzhiyun {
204*4882a593Smuzhiyun 	struct ddb_input *input = fe->sec_priv;
205*4882a593Smuzhiyun 	struct ddb_port *port = input->port;
206*4882a593Smuzhiyun 	struct ddb *dev = port->dev;
207*4882a593Smuzhiyun 	struct ddb_dvb *dvb = &port->dvb[input->nr & 1];
208*4882a593Smuzhiyun 	int tuner = 0;
209*4882a593Smuzhiyun 	int res = 0;
210*4882a593Smuzhiyun 	u32 fmode = dev->link[port->lnr].lnb.fmode;
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	mutex_lock(&dev->link[port->lnr].lnb.lock);
213*4882a593Smuzhiyun 	dvb->tone = tone;
214*4882a593Smuzhiyun 	switch (fmode) {
215*4882a593Smuzhiyun 	default:
216*4882a593Smuzhiyun 	case 0:
217*4882a593Smuzhiyun 	case 3:
218*4882a593Smuzhiyun 		res = lnb_set_tone(dev, port->lnr, dvb->input, tone);
219*4882a593Smuzhiyun 		break;
220*4882a593Smuzhiyun 	case 1:
221*4882a593Smuzhiyun 	case 2:
222*4882a593Smuzhiyun 		if (old_quattro) {
223*4882a593Smuzhiyun 			if (dvb->tone == SEC_TONE_ON)
224*4882a593Smuzhiyun 				tuner |= 2;
225*4882a593Smuzhiyun 			if (dvb->voltage == SEC_VOLTAGE_18)
226*4882a593Smuzhiyun 				tuner |= 1;
227*4882a593Smuzhiyun 		} else {
228*4882a593Smuzhiyun 			if (dvb->tone == SEC_TONE_ON)
229*4882a593Smuzhiyun 				tuner |= 1;
230*4882a593Smuzhiyun 			if (dvb->voltage == SEC_VOLTAGE_18)
231*4882a593Smuzhiyun 				tuner |= 2;
232*4882a593Smuzhiyun 		}
233*4882a593Smuzhiyun 		res = max_set_input_unlocked(fe, tuner);
234*4882a593Smuzhiyun 		break;
235*4882a593Smuzhiyun 	}
236*4882a593Smuzhiyun 	mutex_unlock(&dev->link[port->lnr].lnb.lock);
237*4882a593Smuzhiyun 	return res;
238*4882a593Smuzhiyun }
239*4882a593Smuzhiyun 
max_set_voltage(struct dvb_frontend * fe,enum fe_sec_voltage voltage)240*4882a593Smuzhiyun static int max_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage voltage)
241*4882a593Smuzhiyun {
242*4882a593Smuzhiyun 	struct ddb_input *input = fe->sec_priv;
243*4882a593Smuzhiyun 	struct ddb_port *port = input->port;
244*4882a593Smuzhiyun 	struct ddb *dev = port->dev;
245*4882a593Smuzhiyun 	struct ddb_dvb *dvb = &port->dvb[input->nr & 1];
246*4882a593Smuzhiyun 	int tuner = 0;
247*4882a593Smuzhiyun 	u32 nv, ov = dev->link[port->lnr].lnb.voltages;
248*4882a593Smuzhiyun 	int res = 0;
249*4882a593Smuzhiyun 	u32 fmode = dev->link[port->lnr].lnb.fmode;
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	mutex_lock(&dev->link[port->lnr].lnb.lock);
252*4882a593Smuzhiyun 	dvb->voltage = voltage;
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	switch (fmode) {
255*4882a593Smuzhiyun 	case 3:
256*4882a593Smuzhiyun 	default:
257*4882a593Smuzhiyun 	case 0:
258*4882a593Smuzhiyun 		if (fmode == 3)
259*4882a593Smuzhiyun 			max_set_input_unlocked(fe, 0);
260*4882a593Smuzhiyun 		if (voltage == SEC_VOLTAGE_OFF)
261*4882a593Smuzhiyun 			dev->link[port->lnr].lnb.voltage[dvb->input] &=
262*4882a593Smuzhiyun 				~(1ULL << input->nr);
263*4882a593Smuzhiyun 		else
264*4882a593Smuzhiyun 			dev->link[port->lnr].lnb.voltage[dvb->input] |=
265*4882a593Smuzhiyun 				(1ULL << input->nr);
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 		res = lnb_set_voltage(dev, port->lnr, dvb->input, voltage);
268*4882a593Smuzhiyun 		break;
269*4882a593Smuzhiyun 	case 1:
270*4882a593Smuzhiyun 	case 2:
271*4882a593Smuzhiyun 		if (voltage == SEC_VOLTAGE_OFF)
272*4882a593Smuzhiyun 			dev->link[port->lnr].lnb.voltages &=
273*4882a593Smuzhiyun 				~(1ULL << input->nr);
274*4882a593Smuzhiyun 		else
275*4882a593Smuzhiyun 			dev->link[port->lnr].lnb.voltages |=
276*4882a593Smuzhiyun 				(1ULL << input->nr);
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 		nv = dev->link[port->lnr].lnb.voltages;
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 		if (old_quattro) {
281*4882a593Smuzhiyun 			if (dvb->tone == SEC_TONE_ON)
282*4882a593Smuzhiyun 				tuner |= 2;
283*4882a593Smuzhiyun 			if (dvb->voltage == SEC_VOLTAGE_18)
284*4882a593Smuzhiyun 				tuner |= 1;
285*4882a593Smuzhiyun 		} else {
286*4882a593Smuzhiyun 			if (dvb->tone == SEC_TONE_ON)
287*4882a593Smuzhiyun 				tuner |= 1;
288*4882a593Smuzhiyun 			if (dvb->voltage == SEC_VOLTAGE_18)
289*4882a593Smuzhiyun 				tuner |= 2;
290*4882a593Smuzhiyun 		}
291*4882a593Smuzhiyun 		res = max_set_input_unlocked(fe, tuner);
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 		if (nv != ov) {
294*4882a593Smuzhiyun 			if (nv) {
295*4882a593Smuzhiyun 				lnb_set_voltage(
296*4882a593Smuzhiyun 					dev, port->lnr,
297*4882a593Smuzhiyun 					0, SEC_VOLTAGE_13);
298*4882a593Smuzhiyun 				if (fmode == 1) {
299*4882a593Smuzhiyun 					lnb_set_voltage(
300*4882a593Smuzhiyun 						dev, port->lnr,
301*4882a593Smuzhiyun 						0, SEC_VOLTAGE_13);
302*4882a593Smuzhiyun 					if (old_quattro) {
303*4882a593Smuzhiyun 						lnb_set_voltage(
304*4882a593Smuzhiyun 							dev, port->lnr,
305*4882a593Smuzhiyun 							1, SEC_VOLTAGE_18);
306*4882a593Smuzhiyun 						lnb_set_voltage(
307*4882a593Smuzhiyun 							dev, port->lnr,
308*4882a593Smuzhiyun 							2, SEC_VOLTAGE_13);
309*4882a593Smuzhiyun 					} else {
310*4882a593Smuzhiyun 						lnb_set_voltage(
311*4882a593Smuzhiyun 							dev, port->lnr,
312*4882a593Smuzhiyun 							1, SEC_VOLTAGE_13);
313*4882a593Smuzhiyun 						lnb_set_voltage(
314*4882a593Smuzhiyun 							dev, port->lnr,
315*4882a593Smuzhiyun 							2, SEC_VOLTAGE_18);
316*4882a593Smuzhiyun 					}
317*4882a593Smuzhiyun 					lnb_set_voltage(
318*4882a593Smuzhiyun 						dev, port->lnr,
319*4882a593Smuzhiyun 						3, SEC_VOLTAGE_18);
320*4882a593Smuzhiyun 				}
321*4882a593Smuzhiyun 			} else {
322*4882a593Smuzhiyun 				lnb_set_voltage(
323*4882a593Smuzhiyun 					dev, port->lnr,
324*4882a593Smuzhiyun 					0, SEC_VOLTAGE_OFF);
325*4882a593Smuzhiyun 				if (fmode == 1) {
326*4882a593Smuzhiyun 					lnb_set_voltage(
327*4882a593Smuzhiyun 						dev, port->lnr,
328*4882a593Smuzhiyun 						1, SEC_VOLTAGE_OFF);
329*4882a593Smuzhiyun 					lnb_set_voltage(
330*4882a593Smuzhiyun 						dev, port->lnr,
331*4882a593Smuzhiyun 						2, SEC_VOLTAGE_OFF);
332*4882a593Smuzhiyun 					lnb_set_voltage(
333*4882a593Smuzhiyun 						dev, port->lnr,
334*4882a593Smuzhiyun 						3, SEC_VOLTAGE_OFF);
335*4882a593Smuzhiyun 				}
336*4882a593Smuzhiyun 			}
337*4882a593Smuzhiyun 		}
338*4882a593Smuzhiyun 		break;
339*4882a593Smuzhiyun 	}
340*4882a593Smuzhiyun 	mutex_unlock(&dev->link[port->lnr].lnb.lock);
341*4882a593Smuzhiyun 	return res;
342*4882a593Smuzhiyun }
343*4882a593Smuzhiyun 
max_enable_high_lnb_voltage(struct dvb_frontend * fe,long arg)344*4882a593Smuzhiyun static int max_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
345*4882a593Smuzhiyun {
346*4882a593Smuzhiyun 	return 0;
347*4882a593Smuzhiyun }
348*4882a593Smuzhiyun 
max_send_burst(struct dvb_frontend * fe,enum fe_sec_mini_cmd burst)349*4882a593Smuzhiyun static int max_send_burst(struct dvb_frontend *fe, enum fe_sec_mini_cmd burst)
350*4882a593Smuzhiyun {
351*4882a593Smuzhiyun 	return 0;
352*4882a593Smuzhiyun }
353*4882a593Smuzhiyun 
mxl_fw_read(void * priv,u8 * buf,u32 len)354*4882a593Smuzhiyun static int mxl_fw_read(void *priv, u8 *buf, u32 len)
355*4882a593Smuzhiyun {
356*4882a593Smuzhiyun 	struct ddb_link *link = priv;
357*4882a593Smuzhiyun 	struct ddb *dev = link->dev;
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	dev_info(dev->dev, "Read mxl_fw from link %u\n", link->nr);
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	return ddbridge_flashread(dev, link->nr, buf, 0xc0000, len);
362*4882a593Smuzhiyun }
363*4882a593Smuzhiyun 
ddb_lnb_init_fmode(struct ddb * dev,struct ddb_link * link,u32 fm)364*4882a593Smuzhiyun int ddb_lnb_init_fmode(struct ddb *dev, struct ddb_link *link, u32 fm)
365*4882a593Smuzhiyun {
366*4882a593Smuzhiyun 	u32 l = link->nr;
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 	if (link->lnb.fmode == fm)
369*4882a593Smuzhiyun 		return 0;
370*4882a593Smuzhiyun 	dev_info(dev->dev, "Set fmode link %u = %u\n", l, fm);
371*4882a593Smuzhiyun 	mutex_lock(&link->lnb.lock);
372*4882a593Smuzhiyun 	if (fm == 2 || fm == 1) {
373*4882a593Smuzhiyun 		if (fmode_sat >= 0) {
374*4882a593Smuzhiyun 			lnb_set_sat(dev, l, 0, fmode_sat, 0, 0);
375*4882a593Smuzhiyun 			if (old_quattro) {
376*4882a593Smuzhiyun 				lnb_set_sat(dev, l, 1, fmode_sat, 0, 1);
377*4882a593Smuzhiyun 				lnb_set_sat(dev, l, 2, fmode_sat, 1, 0);
378*4882a593Smuzhiyun 			} else {
379*4882a593Smuzhiyun 				lnb_set_sat(dev, l, 1, fmode_sat, 1, 0);
380*4882a593Smuzhiyun 				lnb_set_sat(dev, l, 2, fmode_sat, 0, 1);
381*4882a593Smuzhiyun 			}
382*4882a593Smuzhiyun 			lnb_set_sat(dev, l, 3, fmode_sat, 1, 1);
383*4882a593Smuzhiyun 		}
384*4882a593Smuzhiyun 		lnb_set_tone(dev, l, 0, SEC_TONE_OFF);
385*4882a593Smuzhiyun 		if (old_quattro) {
386*4882a593Smuzhiyun 			lnb_set_tone(dev, l, 1, SEC_TONE_OFF);
387*4882a593Smuzhiyun 			lnb_set_tone(dev, l, 2, SEC_TONE_ON);
388*4882a593Smuzhiyun 		} else {
389*4882a593Smuzhiyun 			lnb_set_tone(dev, l, 1, SEC_TONE_ON);
390*4882a593Smuzhiyun 			lnb_set_tone(dev, l, 2, SEC_TONE_OFF);
391*4882a593Smuzhiyun 		}
392*4882a593Smuzhiyun 		lnb_set_tone(dev, l, 3, SEC_TONE_ON);
393*4882a593Smuzhiyun 	}
394*4882a593Smuzhiyun 	link->lnb.fmode = fm;
395*4882a593Smuzhiyun 	mutex_unlock(&link->lnb.lock);
396*4882a593Smuzhiyun 	return 0;
397*4882a593Smuzhiyun }
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun static struct mxl5xx_cfg mxl5xx = {
400*4882a593Smuzhiyun 	.adr      = 0x60,
401*4882a593Smuzhiyun 	.type     = 0x01,
402*4882a593Smuzhiyun 	.clk      = 27000000,
403*4882a593Smuzhiyun 	.ts_clk   = 139,
404*4882a593Smuzhiyun 	.cap      = 12,
405*4882a593Smuzhiyun 	.fw_read  = mxl_fw_read,
406*4882a593Smuzhiyun };
407*4882a593Smuzhiyun 
ddb_fe_attach_mxl5xx(struct ddb_input * input)408*4882a593Smuzhiyun int ddb_fe_attach_mxl5xx(struct ddb_input *input)
409*4882a593Smuzhiyun {
410*4882a593Smuzhiyun 	struct ddb *dev = input->port->dev;
411*4882a593Smuzhiyun 	struct i2c_adapter *i2c = &input->port->i2c->adap;
412*4882a593Smuzhiyun 	struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1];
413*4882a593Smuzhiyun 	struct ddb_port *port = input->port;
414*4882a593Smuzhiyun 	struct ddb_link *link = &dev->link[port->lnr];
415*4882a593Smuzhiyun 	struct mxl5xx_cfg cfg;
416*4882a593Smuzhiyun 	int demod, tuner;
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 	cfg = mxl5xx;
419*4882a593Smuzhiyun 	cfg.fw_priv = link;
420*4882a593Smuzhiyun 	dvb->set_input = NULL;
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 	demod = input->nr;
423*4882a593Smuzhiyun 	tuner = demod & 3;
424*4882a593Smuzhiyun 	if (fmode == 3)
425*4882a593Smuzhiyun 		tuner = 0;
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 	dvb->fe = dvb_attach(mxl5xx_attach, i2c, &cfg,
428*4882a593Smuzhiyun 			     demod, tuner, &dvb->set_input);
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 	if (!dvb->fe) {
431*4882a593Smuzhiyun 		dev_err(dev->dev, "No MXL5XX found!\n");
432*4882a593Smuzhiyun 		return -ENODEV;
433*4882a593Smuzhiyun 	}
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun 	if (!dvb->set_input) {
436*4882a593Smuzhiyun 		dev_err(dev->dev, "No mxl5xx_set_input function pointer!\n");
437*4882a593Smuzhiyun 		return -ENODEV;
438*4882a593Smuzhiyun 	}
439*4882a593Smuzhiyun 
440*4882a593Smuzhiyun 	if (input->nr < 4) {
441*4882a593Smuzhiyun 		lnb_command(dev, port->lnr, input->nr, LNB_CMD_INIT);
442*4882a593Smuzhiyun 		lnb_set_voltage(dev, port->lnr, input->nr, SEC_VOLTAGE_OFF);
443*4882a593Smuzhiyun 	}
444*4882a593Smuzhiyun 	ddb_lnb_init_fmode(dev, link, fmode);
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 	dvb->fe->ops.set_voltage = max_set_voltage;
447*4882a593Smuzhiyun 	dvb->fe->ops.enable_high_lnb_voltage = max_enable_high_lnb_voltage;
448*4882a593Smuzhiyun 	dvb->fe->ops.set_tone = max_set_tone;
449*4882a593Smuzhiyun 	dvb->diseqc_send_master_cmd = dvb->fe->ops.diseqc_send_master_cmd;
450*4882a593Smuzhiyun 	dvb->fe->ops.diseqc_send_master_cmd = max_send_master_cmd;
451*4882a593Smuzhiyun 	dvb->fe->ops.diseqc_send_burst = max_send_burst;
452*4882a593Smuzhiyun 	dvb->fe->sec_priv = input;
453*4882a593Smuzhiyun 	dvb->input = tuner;
454*4882a593Smuzhiyun 	return 0;
455*4882a593Smuzhiyun }
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun /******************************************************************************/
458*4882a593Smuzhiyun /* MAX MCI related functions */
459*4882a593Smuzhiyun 
ddb_fe_attach_mci(struct ddb_input * input,u32 type)460*4882a593Smuzhiyun int ddb_fe_attach_mci(struct ddb_input *input, u32 type)
461*4882a593Smuzhiyun {
462*4882a593Smuzhiyun 	struct ddb *dev = input->port->dev;
463*4882a593Smuzhiyun 	struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1];
464*4882a593Smuzhiyun 	struct ddb_port *port = input->port;
465*4882a593Smuzhiyun 	struct ddb_link *link = &dev->link[port->lnr];
466*4882a593Smuzhiyun 	int demod, tuner;
467*4882a593Smuzhiyun 	struct mci_cfg cfg;
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun 	demod = input->nr;
470*4882a593Smuzhiyun 	tuner = demod & 3;
471*4882a593Smuzhiyun 	switch (type) {
472*4882a593Smuzhiyun 	case DDB_TUNER_MCI_SX8:
473*4882a593Smuzhiyun 		cfg = ddb_max_sx8_cfg;
474*4882a593Smuzhiyun 		if (fmode == 3)
475*4882a593Smuzhiyun 			tuner = 0;
476*4882a593Smuzhiyun 		break;
477*4882a593Smuzhiyun 	default:
478*4882a593Smuzhiyun 		return -EINVAL;
479*4882a593Smuzhiyun 	}
480*4882a593Smuzhiyun 	dvb->fe = ddb_mci_attach(input, &cfg, demod, &dvb->set_input);
481*4882a593Smuzhiyun 	if (!dvb->fe) {
482*4882a593Smuzhiyun 		dev_err(dev->dev, "No MCI card found!\n");
483*4882a593Smuzhiyun 		return -ENODEV;
484*4882a593Smuzhiyun 	}
485*4882a593Smuzhiyun 	if (!dvb->set_input) {
486*4882a593Smuzhiyun 		dev_err(dev->dev, "No MCI set_input function pointer!\n");
487*4882a593Smuzhiyun 		return -ENODEV;
488*4882a593Smuzhiyun 	}
489*4882a593Smuzhiyun 	if (input->nr < 4) {
490*4882a593Smuzhiyun 		lnb_command(dev, port->lnr, input->nr, LNB_CMD_INIT);
491*4882a593Smuzhiyun 		lnb_set_voltage(dev, port->lnr, input->nr, SEC_VOLTAGE_OFF);
492*4882a593Smuzhiyun 	}
493*4882a593Smuzhiyun 	ddb_lnb_init_fmode(dev, link, fmode);
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun 	dvb->fe->ops.set_voltage = max_set_voltage;
496*4882a593Smuzhiyun 	dvb->fe->ops.enable_high_lnb_voltage = max_enable_high_lnb_voltage;
497*4882a593Smuzhiyun 	dvb->fe->ops.set_tone = max_set_tone;
498*4882a593Smuzhiyun 	dvb->diseqc_send_master_cmd = dvb->fe->ops.diseqc_send_master_cmd;
499*4882a593Smuzhiyun 	dvb->fe->ops.diseqc_send_master_cmd = max_send_master_cmd;
500*4882a593Smuzhiyun 	dvb->fe->ops.diseqc_send_burst = max_send_burst;
501*4882a593Smuzhiyun 	dvb->fe->sec_priv = input;
502*4882a593Smuzhiyun 	dvb->input = tuner;
503*4882a593Smuzhiyun 	return 0;
504*4882a593Smuzhiyun }
505