brintos

brintos / linux-shallow public Read only

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