172 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * lnbp21.c - driver for lnb supply and control ic lnbp214 *5 * Copyright (C) 2006, 2009 Oliver Endriss <o.endriss@gmx.de>6 * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>7 *8 * the project's page is at https://linuxtv.org9 */10#include <linux/delay.h>11#include <linux/errno.h>12#include <linux/init.h>13#include <linux/kernel.h>14#include <linux/module.h>15#include <linux/string.h>16#include <linux/slab.h>17 18#include <media/dvb_frontend.h>19#include "lnbp21.h"20#include "lnbh24.h"21 22struct lnbp21 {23 u8 config;24 u8 override_or;25 u8 override_and;26 struct i2c_adapter *i2c;27 u8 i2c_addr;28};29 30static int lnbp21_set_voltage(struct dvb_frontend *fe,31 enum fe_sec_voltage voltage)32{33 struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv;34 struct i2c_msg msg = { .addr = lnbp21->i2c_addr, .flags = 0,35 .buf = &lnbp21->config,36 .len = sizeof(lnbp21->config) };37 38 lnbp21->config &= ~(LNBP21_VSEL | LNBP21_EN);39 40 switch(voltage) {41 case SEC_VOLTAGE_OFF:42 break;43 case SEC_VOLTAGE_13:44 lnbp21->config |= LNBP21_EN;45 break;46 case SEC_VOLTAGE_18:47 lnbp21->config |= (LNBP21_EN | LNBP21_VSEL);48 break;49 default:50 return -EINVAL;51 }52 53 lnbp21->config |= lnbp21->override_or;54 lnbp21->config &= lnbp21->override_and;55 56 return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;57}58 59static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)60{61 struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv;62 struct i2c_msg msg = { .addr = lnbp21->i2c_addr, .flags = 0,63 .buf = &lnbp21->config,64 .len = sizeof(lnbp21->config) };65 66 if (arg)67 lnbp21->config |= LNBP21_LLC;68 else69 lnbp21->config &= ~LNBP21_LLC;70 71 lnbp21->config |= lnbp21->override_or;72 lnbp21->config &= lnbp21->override_and;73 74 return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;75}76 77static int lnbp21_set_tone(struct dvb_frontend *fe,78 enum fe_sec_tone_mode tone)79{80 struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv;81 struct i2c_msg msg = { .addr = lnbp21->i2c_addr, .flags = 0,82 .buf = &lnbp21->config,83 .len = sizeof(lnbp21->config) };84 85 switch (tone) {86 case SEC_TONE_OFF:87 lnbp21->config &= ~LNBP21_TEN;88 break;89 case SEC_TONE_ON:90 lnbp21->config |= LNBP21_TEN;91 break;92 default:93 return -EINVAL;94 }95 96 lnbp21->config |= lnbp21->override_or;97 lnbp21->config &= lnbp21->override_and;98 99 return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;100}101 102static void lnbp21_release(struct dvb_frontend *fe)103{104 /* LNBP power off */105 lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF);106 107 /* free data */108 kfree(fe->sec_priv);109 fe->sec_priv = NULL;110}111 112static struct dvb_frontend *lnbx2x_attach(struct dvb_frontend *fe,113 struct i2c_adapter *i2c, u8 override_set,114 u8 override_clear, u8 i2c_addr, u8 config)115{116 struct lnbp21 *lnbp21 = kmalloc(sizeof(struct lnbp21), GFP_KERNEL);117 if (!lnbp21)118 return NULL;119 120 /* default configuration */121 lnbp21->config = config;122 lnbp21->i2c = i2c;123 lnbp21->i2c_addr = i2c_addr;124 fe->sec_priv = lnbp21;125 126 /* bits which should be forced to '1' */127 lnbp21->override_or = override_set;128 129 /* bits which should be forced to '0' */130 lnbp21->override_and = ~override_clear;131 132 /* detect if it is present or not */133 if (lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF)) {134 kfree(lnbp21);135 return NULL;136 }137 138 /* install release callback */139 fe->ops.release_sec = lnbp21_release;140 141 /* override frontend ops */142 fe->ops.set_voltage = lnbp21_set_voltage;143 fe->ops.enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;144 if (!(override_clear & LNBH24_TEN)) /*22kHz logic controlled by demod*/145 fe->ops.set_tone = lnbp21_set_tone;146 printk(KERN_INFO "LNBx2x attached on addr=%x\n", lnbp21->i2c_addr);147 148 return fe;149}150 151struct dvb_frontend *lnbh24_attach(struct dvb_frontend *fe,152 struct i2c_adapter *i2c, u8 override_set,153 u8 override_clear, u8 i2c_addr)154{155 return lnbx2x_attach(fe, i2c, override_set, override_clear,156 i2c_addr, LNBH24_TTX);157}158EXPORT_SYMBOL_GPL(lnbh24_attach);159 160struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe,161 struct i2c_adapter *i2c, u8 override_set,162 u8 override_clear)163{164 return lnbx2x_attach(fe, i2c, override_set, override_clear,165 0x08, LNBP21_ISEL);166}167EXPORT_SYMBOL_GPL(lnbp21_attach);168 169MODULE_DESCRIPTION("Driver for lnb supply and control ic lnbp21, lnbh24");170MODULE_AUTHOR("Oliver Endriss, Igor M. Liplianin");171MODULE_LICENSE("GPL");172