1/* 2 Intersil ISL6423 SEC and LNB Power supply controller 3 4 Copyright (C) Manu Abraham <abraham.manu@gmail.com> 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program; if not, write to the Free Software 18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19*/ 20 21#include <linux/delay.h> 22#include <linux/errno.h> 23#include <linux/init.h> 24#include <linux/kernel.h> 25#include <linux/module.h> 26#include <linux/string.h> 27#include <linux/slab.h> 28 29#include "dvb_frontend.h" 30#include "isl6423.h" 31 32static unsigned int verbose; 33module_param(verbose, int, 0644); 34MODULE_PARM_DESC(verbose, "Set Verbosity level"); 35 36#define FE_ERROR 0 37#define FE_NOTICE 1 38#define FE_INFO 2 39#define FE_DEBUG 3 40#define FE_DEBUGREG 4 41 42#define dprintk(__y, __z, format, arg...) do { \ 43 if (__z) { \ 44 if ((verbose > FE_ERROR) && (verbose > __y)) \ 45 printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \ 46 else if ((verbose > FE_NOTICE) && (verbose > __y)) \ 47 printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \ 48 else if ((verbose > FE_INFO) && (verbose > __y)) \ 49 printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \ 50 else if ((verbose > FE_DEBUG) && (verbose > __y)) \ 51 printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \ 52 } else { \ 53 if (verbose > __y) \ 54 printk(format, ##arg); \ 55 } \ 56} while (0) 57 58struct isl6423_dev { 59 const struct isl6423_config *config; 60 struct i2c_adapter *i2c; 61 62 u8 reg_3; 63 u8 reg_4; 64 65 unsigned int verbose; 66}; 67 68static int isl6423_write(struct isl6423_dev *isl6423, u8 reg) 69{ 70 struct i2c_adapter *i2c = isl6423->i2c; 71 u8 addr = isl6423->config->addr; 72 int err = 0; 73 74 struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = ®, .len = 1 }; 75 76 dprintk(FE_DEBUG, 1, "write reg %02X", reg); 77 err = i2c_transfer(i2c, &msg, 1); 78 if (err < 0) 79 goto exit; 80 return 0; 81 82exit: 83 dprintk(FE_ERROR, 1, "I/O error <%d>", err); 84 return err; 85} 86 87static int isl6423_set_modulation(struct dvb_frontend *fe) 88{ 89 struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv; 90 const struct isl6423_config *config = isl6423->config; 91 int err = 0; 92 u8 reg_2 = 0; 93 94 reg_2 = 0x01 << 5; 95 96 if (config->mod_extern) 97 reg_2 |= (1 << 3); 98 else 99 reg_2 |= (1 << 4); 100 101 err = isl6423_write(isl6423, reg_2); 102 if (err < 0) 103 goto exit; 104 return 0; 105 106exit: 107 dprintk(FE_ERROR, 1, "I/O error <%d>", err); 108 return err; 109} 110 111static int isl6423_voltage_boost(struct dvb_frontend *fe, long arg) 112{ 113 struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv; 114 u8 reg_3 = isl6423->reg_3; 115 u8 reg_4 = isl6423->reg_4; 116 int err = 0; 117 118 if (arg) { 119 /* EN = 1, VSPEN = 1, VBOT = 1 */ 120 reg_4 |= (1 << 4); 121 reg_4 |= 0x1; 122 reg_3 |= (1 << 3); 123 } else { 124 /* EN = 1, VSPEN = 1, VBOT = 0 */ 125 reg_4 |= (1 << 4); 126 reg_4 &= ~0x1; 127 reg_3 |= (1 << 3); 128 } 129 err = isl6423_write(isl6423, reg_3); 130 if (err < 0) 131 goto exit; 132 133 err = isl6423_write(isl6423, reg_4); 134 if (err < 0) 135 goto exit; 136 137 isl6423->reg_3 = reg_3; 138 isl6423->reg_4 = reg_4; 139 140 return 0; 141exit: 142 dprintk(FE_ERROR, 1, "I/O error <%d>", err); 143 return err; 144} 145 146 147static int isl6423_set_voltage(struct dvb_frontend *fe, 148 enum fe_sec_voltage voltage) 149{ 150 struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv; 151 u8 reg_3 = isl6423->reg_3; 152 u8 reg_4 = isl6423->reg_4; 153 int err = 0; 154 155 switch (voltage) { 156 case SEC_VOLTAGE_OFF: 157 /* EN = 0 */ 158 reg_4 &= ~(1 << 4); 159 break; 160 161 case SEC_VOLTAGE_13: 162 /* EN = 1, VSPEN = 1, VTOP = 0, VBOT = 0 */ 163 reg_4 |= (1 << 4); 164 reg_4 &= ~0x3; 165 reg_3 |= (1 << 3); 166 break; 167 168 case SEC_VOLTAGE_18: 169 /* EN = 1, VSPEN = 1, VTOP = 1, VBOT = 0 */ 170 reg_4 |= (1 << 4); 171 reg_4 |= 0x2; 172 reg_4 &= ~0x1; 173 reg_3 |= (1 << 3); 174 break; 175 176 default: 177 break; 178 } 179 err = isl6423_write(isl6423, reg_3); 180 if (err < 0) 181 goto exit; 182 183 err = isl6423_write(isl6423, reg_4); 184 if (err < 0) 185 goto exit; 186 187 isl6423->reg_3 = reg_3; 188 isl6423->reg_4 = reg_4; 189 190 return 0; 191exit: 192 dprintk(FE_ERROR, 1, "I/O error <%d>", err); 193 return err; 194} 195 196static int isl6423_set_current(struct dvb_frontend *fe) 197{ 198 struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv; 199 u8 reg_3 = isl6423->reg_3; 200 const struct isl6423_config *config = isl6423->config; 201 int err = 0; 202 203 switch (config->current_max) { 204 case SEC_CURRENT_275m: 205 /* 275mA */ 206 /* ISELH = 0, ISELL = 0 */ 207 reg_3 &= ~0x3; 208 break; 209 210 case SEC_CURRENT_515m: 211 /* 515mA */ 212 /* ISELH = 0, ISELL = 1 */ 213 reg_3 &= ~0x2; 214 reg_3 |= 0x1; 215 break; 216 217 case SEC_CURRENT_635m: 218 /* 635mA */ 219 /* ISELH = 1, ISELL = 0 */ 220 reg_3 &= ~0x1; 221 reg_3 |= 0x2; 222 break; 223 224 case SEC_CURRENT_800m: 225 /* 800mA */ 226 /* ISELH = 1, ISELL = 1 */ 227 reg_3 |= 0x3; 228 break; 229 } 230 231 err = isl6423_write(isl6423, reg_3); 232 if (err < 0) 233 goto exit; 234 235 switch (config->curlim) { 236 case SEC_CURRENT_LIM_ON: 237 /* DCL = 0 */ 238 reg_3 &= ~0x10; 239 break; 240 241 case SEC_CURRENT_LIM_OFF: 242 /* DCL = 1 */ 243 reg_3 |= 0x10; 244 break; 245 } 246 247 err = isl6423_write(isl6423, reg_3); 248 if (err < 0) 249 goto exit; 250 251 isl6423->reg_3 = reg_3; 252 253 return 0; 254exit: 255 dprintk(FE_ERROR, 1, "I/O error <%d>", err); 256 return err; 257} 258 259static void isl6423_release(struct dvb_frontend *fe) 260{ 261 isl6423_set_voltage(fe, SEC_VOLTAGE_OFF); 262 263 kfree(fe->sec_priv); 264 fe->sec_priv = NULL; 265} 266 267struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe, 268 struct i2c_adapter *i2c, 269 const struct isl6423_config *config) 270{ 271 struct isl6423_dev *isl6423; 272 273 isl6423 = kzalloc(sizeof(struct isl6423_dev), GFP_KERNEL); 274 if (!isl6423) 275 return NULL; 276 277 isl6423->config = config; 278 isl6423->i2c = i2c; 279 fe->sec_priv = isl6423; 280 281 /* SR3H = 0, SR3M = 1, SR3L = 0 */ 282 isl6423->reg_3 = 0x02 << 5; 283 /* SR4H = 0, SR4M = 1, SR4L = 1 */ 284 isl6423->reg_4 = 0x03 << 5; 285 286 if (isl6423_set_current(fe)) 287 goto exit; 288 289 if (isl6423_set_modulation(fe)) 290 goto exit; 291 292 fe->ops.release_sec = isl6423_release; 293 fe->ops.set_voltage = isl6423_set_voltage; 294 fe->ops.enable_high_lnb_voltage = isl6423_voltage_boost; 295 isl6423->verbose = verbose; 296 297 return fe; 298 299exit: 300 kfree(isl6423); 301 fe->sec_priv = NULL; 302 return NULL; 303} 304EXPORT_SYMBOL(isl6423_attach); 305 306MODULE_DESCRIPTION("ISL6423 SEC"); 307MODULE_AUTHOR("Manu Abraham"); 308MODULE_LICENSE("GPL"); 309