1 /* 2 * isl6405.c - driver for dual lnb supply and control ic ISL6405 3 * 4 * Copyright (C) 2008 Hartmut Hackmann 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 <media/dvb_frontend.h> 33 #include "isl6405.h" 34 35 struct isl6405 { 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 isl6405_set_voltage(struct dvb_frontend *fe, 44 enum fe_sec_voltage voltage) 45 { 46 struct isl6405 *isl6405 = (struct isl6405 *) fe->sec_priv; 47 struct i2c_msg msg = { .addr = isl6405->i2c_addr, .flags = 0, 48 .buf = &isl6405->config, 49 .len = sizeof(isl6405->config) }; 50 51 if (isl6405->override_or & 0x80) { 52 isl6405->config &= ~(ISL6405_VSEL2 | ISL6405_EN2); 53 switch (voltage) { 54 case SEC_VOLTAGE_OFF: 55 break; 56 case SEC_VOLTAGE_13: 57 isl6405->config |= ISL6405_EN2; 58 break; 59 case SEC_VOLTAGE_18: 60 isl6405->config |= (ISL6405_EN2 | ISL6405_VSEL2); 61 break; 62 default: 63 return -EINVAL; 64 } 65 } else { 66 isl6405->config &= ~(ISL6405_VSEL1 | ISL6405_EN1); 67 switch (voltage) { 68 case SEC_VOLTAGE_OFF: 69 break; 70 case SEC_VOLTAGE_13: 71 isl6405->config |= ISL6405_EN1; 72 break; 73 case SEC_VOLTAGE_18: 74 isl6405->config |= (ISL6405_EN1 | ISL6405_VSEL1); 75 break; 76 default: 77 return -EINVAL; 78 } 79 } 80 isl6405->config |= isl6405->override_or; 81 isl6405->config &= isl6405->override_and; 82 83 return (i2c_transfer(isl6405->i2c, &msg, 1) == 1) ? 0 : -EIO; 84 } 85 86 static int isl6405_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg) 87 { 88 struct isl6405 *isl6405 = (struct isl6405 *) fe->sec_priv; 89 struct i2c_msg msg = { .addr = isl6405->i2c_addr, .flags = 0, 90 .buf = &isl6405->config, 91 .len = sizeof(isl6405->config) }; 92 93 if (isl6405->override_or & 0x80) { 94 if (arg) 95 isl6405->config |= ISL6405_LLC2; 96 else 97 isl6405->config &= ~ISL6405_LLC2; 98 } else { 99 if (arg) 100 isl6405->config |= ISL6405_LLC1; 101 else 102 isl6405->config &= ~ISL6405_LLC1; 103 } 104 isl6405->config |= isl6405->override_or; 105 isl6405->config &= isl6405->override_and; 106 107 return (i2c_transfer(isl6405->i2c, &msg, 1) == 1) ? 0 : -EIO; 108 } 109 110 static void isl6405_release(struct dvb_frontend *fe) 111 { 112 /* power off */ 113 isl6405_set_voltage(fe, SEC_VOLTAGE_OFF); 114 115 /* free */ 116 kfree(fe->sec_priv); 117 fe->sec_priv = NULL; 118 } 119 120 struct dvb_frontend *isl6405_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, 121 u8 i2c_addr, u8 override_set, u8 override_clear) 122 { 123 struct isl6405 *isl6405 = kmalloc(sizeof(struct isl6405), GFP_KERNEL); 124 if (!isl6405) 125 return NULL; 126 127 /* default configuration */ 128 if (override_set & 0x80) 129 isl6405->config = ISL6405_ISEL2; 130 else 131 isl6405->config = ISL6405_ISEL1; 132 isl6405->i2c = i2c; 133 isl6405->i2c_addr = i2c_addr; 134 fe->sec_priv = isl6405; 135 136 /* bits which should be forced to '1' */ 137 isl6405->override_or = override_set; 138 139 /* bits which should be forced to '0' */ 140 isl6405->override_and = ~override_clear; 141 142 /* detect if it is present or not */ 143 if (isl6405_set_voltage(fe, SEC_VOLTAGE_OFF)) { 144 kfree(isl6405); 145 fe->sec_priv = NULL; 146 return NULL; 147 } 148 149 /* install release callback */ 150 fe->ops.release_sec = isl6405_release; 151 152 /* override frontend ops */ 153 fe->ops.set_voltage = isl6405_set_voltage; 154 fe->ops.enable_high_lnb_voltage = isl6405_enable_high_lnb_voltage; 155 156 return fe; 157 } 158 EXPORT_SYMBOL(isl6405_attach); 159 160 MODULE_DESCRIPTION("Driver for lnb supply and control ic isl6405"); 161 MODULE_AUTHOR("Hartmut Hackmann & Oliver Endriss"); 162 MODULE_LICENSE("GPL"); 163