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