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