Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003     Intersil ISL6423 SEC and LNB Power supply controller
0004 
0005     Copyright (C) Manu Abraham <abraham.manu@gmail.com>
0006 
0007 */
0008 
0009 #include <linux/delay.h>
0010 #include <linux/errno.h>
0011 #include <linux/init.h>
0012 #include <linux/kernel.h>
0013 #include <linux/module.h>
0014 #include <linux/string.h>
0015 #include <linux/slab.h>
0016 
0017 #include <media/dvb_frontend.h>
0018 #include "isl6423.h"
0019 
0020 static unsigned int verbose;
0021 module_param(verbose, int, 0644);
0022 MODULE_PARM_DESC(verbose, "Set Verbosity level");
0023 
0024 #define FE_ERROR                0
0025 #define FE_NOTICE               1
0026 #define FE_INFO                 2
0027 #define FE_DEBUG                3
0028 #define FE_DEBUGREG             4
0029 
0030 #define dprintk(__y, __z, format, arg...) do {                      \
0031     if (__z) {                                  \
0032         if  ((verbose > FE_ERROR) && (verbose > __y))           \
0033             printk(KERN_ERR "%s: " format "\n", __func__ , ##arg);      \
0034         else if ((verbose > FE_NOTICE) && (verbose > __y))          \
0035             printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg);   \
0036         else if ((verbose > FE_INFO) && (verbose > __y))            \
0037             printk(KERN_INFO "%s: " format "\n", __func__ , ##arg);     \
0038         else if ((verbose > FE_DEBUG) && (verbose > __y))           \
0039             printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg);    \
0040     } else {                                    \
0041         if (verbose > __y)                          \
0042             printk(format, ##arg);                      \
0043     }                                       \
0044 } while (0)
0045 
0046 struct isl6423_dev {
0047     const struct isl6423_config *config;
0048     struct i2c_adapter      *i2c;
0049 
0050     u8 reg_3;
0051     u8 reg_4;
0052 
0053     unsigned int verbose;
0054 };
0055 
0056 static int isl6423_write(struct isl6423_dev *isl6423, u8 reg)
0057 {
0058     struct i2c_adapter *i2c = isl6423->i2c;
0059     u8 addr         = isl6423->config->addr;
0060     int err = 0;
0061 
0062     struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = &reg, .len = 1 };
0063 
0064     dprintk(FE_DEBUG, 1, "write reg %02X", reg);
0065     err = i2c_transfer(i2c, &msg, 1);
0066     if (err < 0)
0067         goto exit;
0068     return 0;
0069 
0070 exit:
0071     dprintk(FE_ERROR, 1, "I/O error <%d>", err);
0072     return err;
0073 }
0074 
0075 static int isl6423_set_modulation(struct dvb_frontend *fe)
0076 {
0077     struct isl6423_dev *isl6423     = (struct isl6423_dev *) fe->sec_priv;
0078     const struct isl6423_config *config = isl6423->config;
0079     int err = 0;
0080     u8 reg_2 = 0;
0081 
0082     reg_2 = 0x01 << 5;
0083 
0084     if (config->mod_extern)
0085         reg_2 |= (1 << 3);
0086     else
0087         reg_2 |= (1 << 4);
0088 
0089     err = isl6423_write(isl6423, reg_2);
0090     if (err < 0)
0091         goto exit;
0092     return 0;
0093 
0094 exit:
0095     dprintk(FE_ERROR, 1, "I/O error <%d>", err);
0096     return err;
0097 }
0098 
0099 static int isl6423_voltage_boost(struct dvb_frontend *fe, long arg)
0100 {
0101     struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv;
0102     u8 reg_3 = isl6423->reg_3;
0103     u8 reg_4 = isl6423->reg_4;
0104     int err = 0;
0105 
0106     if (arg) {
0107         /* EN = 1, VSPEN = 1, VBOT = 1 */
0108         reg_4 |= (1 << 4);
0109         reg_4 |= 0x1;
0110         reg_3 |= (1 << 3);
0111     } else {
0112         /* EN = 1, VSPEN = 1, VBOT = 0 */
0113         reg_4 |= (1 << 4);
0114         reg_4 &= ~0x1;
0115         reg_3 |= (1 << 3);
0116     }
0117     err = isl6423_write(isl6423, reg_3);
0118     if (err < 0)
0119         goto exit;
0120 
0121     err = isl6423_write(isl6423, reg_4);
0122     if (err < 0)
0123         goto exit;
0124 
0125     isl6423->reg_3 = reg_3;
0126     isl6423->reg_4 = reg_4;
0127 
0128     return 0;
0129 exit:
0130     dprintk(FE_ERROR, 1, "I/O error <%d>", err);
0131     return err;
0132 }
0133 
0134 
0135 static int isl6423_set_voltage(struct dvb_frontend *fe,
0136                    enum fe_sec_voltage voltage)
0137 {
0138     struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv;
0139     u8 reg_3 = isl6423->reg_3;
0140     u8 reg_4 = isl6423->reg_4;
0141     int err = 0;
0142 
0143     switch (voltage) {
0144     case SEC_VOLTAGE_OFF:
0145         /* EN = 0 */
0146         reg_4 &= ~(1 << 4);
0147         break;
0148 
0149     case SEC_VOLTAGE_13:
0150         /* EN = 1, VSPEN = 1, VTOP = 0, VBOT = 0 */
0151         reg_4 |= (1 << 4);
0152         reg_4 &= ~0x3;
0153         reg_3 |= (1 << 3);
0154         break;
0155 
0156     case SEC_VOLTAGE_18:
0157         /* EN = 1, VSPEN = 1, VTOP = 1, VBOT = 0 */
0158         reg_4 |= (1 << 4);
0159         reg_4 |=  0x2;
0160         reg_4 &= ~0x1;
0161         reg_3 |= (1 << 3);
0162         break;
0163 
0164     default:
0165         break;
0166     }
0167     err = isl6423_write(isl6423, reg_3);
0168     if (err < 0)
0169         goto exit;
0170 
0171     err = isl6423_write(isl6423, reg_4);
0172     if (err < 0)
0173         goto exit;
0174 
0175     isl6423->reg_3 = reg_3;
0176     isl6423->reg_4 = reg_4;
0177 
0178     return 0;
0179 exit:
0180     dprintk(FE_ERROR, 1, "I/O error <%d>", err);
0181     return err;
0182 }
0183 
0184 static int isl6423_set_current(struct dvb_frontend *fe)
0185 {
0186     struct isl6423_dev *isl6423     = (struct isl6423_dev *) fe->sec_priv;
0187     u8 reg_3 = isl6423->reg_3;
0188     const struct isl6423_config *config = isl6423->config;
0189     int err = 0;
0190 
0191     switch (config->current_max) {
0192     case SEC_CURRENT_275m:
0193         /* 275mA */
0194         /* ISELH = 0, ISELL = 0 */
0195         reg_3 &= ~0x3;
0196         break;
0197 
0198     case SEC_CURRENT_515m:
0199         /* 515mA */
0200         /* ISELH = 0, ISELL = 1 */
0201         reg_3 &= ~0x2;
0202         reg_3 |=  0x1;
0203         break;
0204 
0205     case SEC_CURRENT_635m:
0206         /* 635mA */
0207         /* ISELH = 1, ISELL = 0 */
0208         reg_3 &= ~0x1;
0209         reg_3 |=  0x2;
0210         break;
0211 
0212     case SEC_CURRENT_800m:
0213         /* 800mA */
0214         /* ISELH = 1, ISELL = 1 */
0215         reg_3 |= 0x3;
0216         break;
0217     }
0218 
0219     err = isl6423_write(isl6423, reg_3);
0220     if (err < 0)
0221         goto exit;
0222 
0223     switch (config->curlim) {
0224     case SEC_CURRENT_LIM_ON:
0225         /* DCL = 0 */
0226         reg_3 &= ~0x10;
0227         break;
0228 
0229     case SEC_CURRENT_LIM_OFF:
0230         /* DCL = 1 */
0231         reg_3 |= 0x10;
0232         break;
0233     }
0234 
0235     err = isl6423_write(isl6423, reg_3);
0236     if (err < 0)
0237         goto exit;
0238 
0239     isl6423->reg_3 = reg_3;
0240 
0241     return 0;
0242 exit:
0243     dprintk(FE_ERROR, 1, "I/O error <%d>", err);
0244     return err;
0245 }
0246 
0247 static void isl6423_release(struct dvb_frontend *fe)
0248 {
0249     isl6423_set_voltage(fe, SEC_VOLTAGE_OFF);
0250 
0251     kfree(fe->sec_priv);
0252     fe->sec_priv = NULL;
0253 }
0254 
0255 struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe,
0256                     struct i2c_adapter *i2c,
0257                     const struct isl6423_config *config)
0258 {
0259     struct isl6423_dev *isl6423;
0260 
0261     isl6423 = kzalloc(sizeof(struct isl6423_dev), GFP_KERNEL);
0262     if (!isl6423)
0263         return NULL;
0264 
0265     isl6423->config = config;
0266     isl6423->i2c    = i2c;
0267     fe->sec_priv    = isl6423;
0268 
0269     /* SR3H = 0, SR3M = 1, SR3L = 0 */
0270     isl6423->reg_3 = 0x02 << 5;
0271     /* SR4H = 0, SR4M = 1, SR4L = 1 */
0272     isl6423->reg_4 = 0x03 << 5;
0273 
0274     if (isl6423_set_current(fe))
0275         goto exit;
0276 
0277     if (isl6423_set_modulation(fe))
0278         goto exit;
0279 
0280     fe->ops.release_sec     = isl6423_release;
0281     fe->ops.set_voltage     = isl6423_set_voltage;
0282     fe->ops.enable_high_lnb_voltage = isl6423_voltage_boost;
0283     isl6423->verbose        = verbose;
0284 
0285     return fe;
0286 
0287 exit:
0288     kfree(isl6423);
0289     fe->sec_priv = NULL;
0290     return NULL;
0291 }
0292 EXPORT_SYMBOL(isl6423_attach);
0293 
0294 MODULE_DESCRIPTION("ISL6423 SEC");
0295 MODULE_AUTHOR("Manu Abraham");
0296 MODULE_LICENSE("GPL");