14e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin/*
24e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin * lnbp22.h - driver for lnb supply and control ic lnbp22
34e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin *
44e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin * Copyright (C) 2006 Dominik Kuhlen
54e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin * Based on lnbp21 driver
64e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin *
74e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin * This program is free software; you can redistribute it and/or
84e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin * modify it under the terms of the GNU General Public License
94e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin * as published by the Free Software Foundation; either version 2
104e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin * of the License, or (at your option) any later version.
114e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin *
124e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin *
134e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin * This program is distributed in the hope that it will be useful,
144e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin * but WITHOUT ANY WARRANTY; without even the implied warranty of
154e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
164e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin * GNU General Public License for more details.
174e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin *
184e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin *
194e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin * You should have received a copy of the GNU General Public License
204e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin * along with this program; if not, write to the Free Software
214e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
224e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
234e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin *
244e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin *
254e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin * the project's page is at http://www.linuxtv.org
264e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin */
274e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin#include <linux/delay.h>
284e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin#include <linux/errno.h>
294e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin#include <linux/init.h>
304e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin#include <linux/kernel.h>
314e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin#include <linux/module.h>
324e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin#include <linux/moduleparam.h>
334e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin#include <linux/string.h>
344e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin#include <linux/slab.h>
354e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin
364e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin#include "dvb_frontend.h"
374e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin#include "lnbp22.h"
384e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin
394e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianinstatic int debug;
404e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianinmodule_param(debug, int, 0644);
414e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. LiplianinMODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
424e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin
434e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin
444e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin#define dprintk(lvl, arg...) if (debug >= (lvl)) printk(arg)
454e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin
464e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianinstruct lnbp22 {
474e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	u8		    config[4];
484e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	struct i2c_adapter *i2c;
494e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin};
504e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin
514e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianinstatic int lnbp22_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
524e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin{
534e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	struct lnbp22 *lnbp22 = (struct lnbp22 *)fe->sec_priv;
544e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	struct i2c_msg msg = {
554e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin		.addr = 0x08,
564e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin		.flags = 0,
574e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin		.buf = (char *)&lnbp22->config,
584e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin		.len = sizeof(lnbp22->config),
594e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	};
604e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin
614e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	dprintk(1, "%s: %d (18V=%d 13V=%d)\n", __func__, voltage,
624e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	       SEC_VOLTAGE_18, SEC_VOLTAGE_13);
634e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin
644e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	lnbp22->config[3] = 0x60; /* Power down */
654e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	switch (voltage) {
664e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	case SEC_VOLTAGE_OFF:
674e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin		break;
684e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	case SEC_VOLTAGE_13:
694e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin		lnbp22->config[3] |= LNBP22_EN;
704e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin		break;
714e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	case SEC_VOLTAGE_18:
724e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin		lnbp22->config[3] |= (LNBP22_EN | LNBP22_VSEL);
734e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin		break;
744e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	default:
754e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin		return -EINVAL;
76c2c1b4156a447f113ef4d167decce29399c2667cPeter Senna Tschudin	}
774e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin
784e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	dprintk(1, "%s: 0x%02x)\n", __func__, lnbp22->config[3]);
794e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	return (i2c_transfer(lnbp22->i2c, &msg, 1) == 1) ? 0 : -EIO;
804e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin}
814e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin
824e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianinstatic int lnbp22_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
834e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin{
844e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	struct lnbp22 *lnbp22 = (struct lnbp22 *) fe->sec_priv;
854e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	struct i2c_msg msg = {
864e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin		.addr = 0x08,
874e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin		.flags = 0,
884e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin		.buf = (char *)&lnbp22->config,
894e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin		.len = sizeof(lnbp22->config),
904e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	};
914e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin
924e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	dprintk(1, "%s: %d\n", __func__, (int)arg);
934e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	if (arg)
944e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin		lnbp22->config[3] |= LNBP22_LLC;
954e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	else
964e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin		lnbp22->config[3] &= ~LNBP22_LLC;
974e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin
984e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	return (i2c_transfer(lnbp22->i2c, &msg, 1) == 1) ? 0 : -EIO;
994e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin}
1004e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin
1014e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianinstatic void lnbp22_release(struct dvb_frontend *fe)
1024e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin{
1034e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	dprintk(1, "%s\n", __func__);
1044e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	/* LNBP power off */
1054e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	lnbp22_set_voltage(fe, SEC_VOLTAGE_OFF);
1064e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin
1074e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	/* free data */
1084e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	kfree(fe->sec_priv);
1094e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	fe->sec_priv = NULL;
1104e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin}
1114e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin
1124e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianinstruct dvb_frontend *lnbp22_attach(struct dvb_frontend *fe,
1134e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin					struct i2c_adapter *i2c)
1144e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin{
1154e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	struct lnbp22 *lnbp22 = kmalloc(sizeof(struct lnbp22), GFP_KERNEL);
1164e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	if (!lnbp22)
1174e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin		return NULL;
1184e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin
1194e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	/* default configuration */
1204e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	lnbp22->config[0] = 0x00; /* ? */
1214e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	lnbp22->config[1] = 0x28; /* ? */
1224e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	lnbp22->config[2] = 0x48; /* ? */
1234e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	lnbp22->config[3] = 0x60; /* Power down */
1244e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	lnbp22->i2c = i2c;
1254e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	fe->sec_priv = lnbp22;
1264e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin
1274e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	/* detect if it is present or not */
1284e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	if (lnbp22_set_voltage(fe, SEC_VOLTAGE_OFF)) {
1294e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin		dprintk(0, "%s LNBP22 not found\n", __func__);
1304e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin		kfree(lnbp22);
1314e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin		fe->sec_priv = NULL;
1324e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin		return NULL;
1334e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	}
1344e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin
1354e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	/* install release callback */
1364e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	fe->ops.release_sec = lnbp22_release;
1374e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin
1384e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	/* override frontend ops */
1394e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	fe->ops.set_voltage = lnbp22_set_voltage;
1404e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	fe->ops.enable_high_lnb_voltage = lnbp22_enable_high_lnb_voltage;
1414e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin
1424e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin	return fe;
1434e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin}
1444e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. LiplianinEXPORT_SYMBOL(lnbp22_attach);
1454e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. Liplianin
1464e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. LiplianinMODULE_DESCRIPTION("Driver for lnb supply and control ic lnbp22");
1474e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. LiplianinMODULE_AUTHOR("Dominik Kuhlen");
1484e2c53fde651be6225d9f940c02b2eabc2f9591cIgor M. LiplianinMODULE_LICENSE("GPL");
149