1 /* 2 * isl6421.h - driver for lnb supply and control ic ISL6421 3 * 4 * Copyright (C) 2006 Andrew de Quincey 5 * Copyright (C) 2006 Oliver Endriss 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 * 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * To obtain the license, point your browser to 19 * http://www.gnu.org/copyleft/gpl.html 20 * 21 * 22 * the project's page is at https://linuxtv.org 23 */ 24 #include <linux/delay.h> 25 #include <linux/errno.h> 26 #include <linux/init.h> 27 #include <linux/kernel.h> 28 #include <linux/module.h> 29 #include <linux/string.h> 30 #include <linux/slab.h> 31 32 #include "dvb_frontend.h" 33 #include "isl6421.h" 34 35 struct isl6421 { 36 u8 config; 37 u8 override_or; 38 u8 override_and; 39 struct i2c_adapter *i2c; 40 u8 i2c_addr; 41 }; 42 43 static int isl6421_set_voltage(struct dvb_frontend *fe, 44 enum fe_sec_voltage voltage) 45 { 46 struct isl6421 *isl6421 = (struct isl6421 *) fe->sec_priv; 47 struct i2c_msg msg = { .addr = isl6421->i2c_addr, .flags = 0, 48 .buf = &isl6421->config, 49 .len = sizeof(isl6421->config) }; 50 51 isl6421->config &= ~(ISL6421_VSEL1 | ISL6421_EN1); 52 53 switch(voltage) { 54 case SEC_VOLTAGE_OFF: 55 break; 56 case SEC_VOLTAGE_13: 57 isl6421->config |= ISL6421_EN1; 58 break; 59 case SEC_VOLTAGE_18: 60 isl6421->config |= (ISL6421_EN1 | ISL6421_VSEL1); 61 break; 62 default: 63 return -EINVAL; 64 } 65 66 isl6421->config |= isl6421->override_or; 67 isl6421->config &= isl6421->override_and; 68 69 return (i2c_transfer(isl6421->i2c, &msg, 1) == 1) ? 0 : -EIO; 70 } 71 72 static int isl6421_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg) 73 { 74 struct isl6421 *isl6421 = (struct isl6421 *) fe->sec_priv; 75 struct i2c_msg msg = { .addr = isl6421->i2c_addr, .flags = 0, 76 .buf = &isl6421->config, 77 .len = sizeof(isl6421->config) }; 78 79 if (arg) 80 isl6421->config |= ISL6421_LLC1; 81 else 82 isl6421->config &= ~ISL6421_LLC1; 83 84 isl6421->config |= isl6421->override_or; 85 isl6421->config &= isl6421->override_and; 86 87 return (i2c_transfer(isl6421->i2c, &msg, 1) == 1) ? 0 : -EIO; 88 } 89 90 static int isl6421_set_tone(struct dvb_frontend *fe, 91 enum fe_sec_tone_mode tone) 92 { 93 struct isl6421 *isl6421 = (struct isl6421 *) fe->sec_priv; 94 struct i2c_msg msg = { .addr = isl6421->i2c_addr, .flags = 0, 95 .buf = &isl6421->config, 96 .len = sizeof(isl6421->config) }; 97 98 switch (tone) { 99 case SEC_TONE_ON: 100 isl6421->config |= ISL6421_ENT1; 101 break; 102 case SEC_TONE_OFF: 103 isl6421->config &= ~ISL6421_ENT1; 104 break; 105 default: 106 return -EINVAL; 107 } 108 109 isl6421->config |= isl6421->override_or; 110 isl6421->config &= isl6421->override_and; 111 112 return (i2c_transfer(isl6421->i2c, &msg, 1) == 1) ? 0 : -EIO; 113 } 114 115 static void isl6421_release(struct dvb_frontend *fe) 116 { 117 /* power off */ 118 isl6421_set_voltage(fe, SEC_VOLTAGE_OFF); 119 120 /* free */ 121 kfree(fe->sec_priv); 122 fe->sec_priv = NULL; 123 } 124 125 struct dvb_frontend *isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr, 126 u8 override_set, u8 override_clear, bool override_tone) 127 { 128 struct isl6421 *isl6421 = kmalloc(sizeof(struct isl6421), GFP_KERNEL); 129 if (!isl6421) 130 return NULL; 131 132 /* default configuration */ 133 isl6421->config = ISL6421_ISEL1; 134 isl6421->i2c = i2c; 135 isl6421->i2c_addr = i2c_addr; 136 fe->sec_priv = isl6421; 137 138 /* bits which should be forced to '1' */ 139 isl6421->override_or = override_set; 140 141 /* bits which should be forced to '0' */ 142 isl6421->override_and = ~override_clear; 143 144 /* detect if it is present or not */ 145 if (isl6421_set_voltage(fe, SEC_VOLTAGE_OFF)) { 146 kfree(isl6421); 147 fe->sec_priv = NULL; 148 return NULL; 149 } 150 151 /* install release callback */ 152 fe->ops.release_sec = isl6421_release; 153 154 /* override frontend ops */ 155 fe->ops.set_voltage = isl6421_set_voltage; 156 fe->ops.enable_high_lnb_voltage = isl6421_enable_high_lnb_voltage; 157 if (override_tone) 158 fe->ops.set_tone = isl6421_set_tone; 159 160 return fe; 161 } 162 EXPORT_SYMBOL(isl6421_attach); 163 164 MODULE_DESCRIPTION("Driver for lnb supply and control ic isl6421"); 165 MODULE_AUTHOR("Andrew de Quincey & Oliver Endriss"); 166 MODULE_LICENSE("GPL"); 167