Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * isl6405.c - driver for dual lnb supply and control ic ISL6405
0004  *
0005  * Copyright (C) 2008 Hartmut Hackmann
0006  * Copyright (C) 2006 Oliver Endriss
0007  *
0008  * the project's page is at https://linuxtv.org
0009  */
0010 #include <linux/delay.h>
0011 #include <linux/errno.h>
0012 #include <linux/init.h>
0013 #include <linux/kernel.h>
0014 #include <linux/module.h>
0015 #include <linux/string.h>
0016 #include <linux/slab.h>
0017 
0018 #include <media/dvb_frontend.h>
0019 #include "isl6405.h"
0020 
0021 struct isl6405 {
0022     u8          config;
0023     u8          override_or;
0024     u8          override_and;
0025     struct i2c_adapter  *i2c;
0026     u8          i2c_addr;
0027 };
0028 
0029 static int isl6405_set_voltage(struct dvb_frontend *fe,
0030                    enum fe_sec_voltage voltage)
0031 {
0032     struct isl6405 *isl6405 = (struct isl6405 *) fe->sec_priv;
0033     struct i2c_msg msg = {  .addr = isl6405->i2c_addr, .flags = 0,
0034                 .buf = &isl6405->config,
0035                 .len = sizeof(isl6405->config) };
0036 
0037     if (isl6405->override_or & 0x80) {
0038         isl6405->config &= ~(ISL6405_VSEL2 | ISL6405_EN2);
0039         switch (voltage) {
0040         case SEC_VOLTAGE_OFF:
0041             break;
0042         case SEC_VOLTAGE_13:
0043             isl6405->config |= ISL6405_EN2;
0044             break;
0045         case SEC_VOLTAGE_18:
0046             isl6405->config |= (ISL6405_EN2 | ISL6405_VSEL2);
0047             break;
0048         default:
0049             return -EINVAL;
0050         }
0051     } else {
0052         isl6405->config &= ~(ISL6405_VSEL1 | ISL6405_EN1);
0053         switch (voltage) {
0054         case SEC_VOLTAGE_OFF:
0055             break;
0056         case SEC_VOLTAGE_13:
0057             isl6405->config |= ISL6405_EN1;
0058             break;
0059         case SEC_VOLTAGE_18:
0060             isl6405->config |= (ISL6405_EN1 | ISL6405_VSEL1);
0061             break;
0062         default:
0063             return -EINVAL;
0064         }
0065     }
0066     isl6405->config |= isl6405->override_or;
0067     isl6405->config &= isl6405->override_and;
0068 
0069     return (i2c_transfer(isl6405->i2c, &msg, 1) == 1) ? 0 : -EIO;
0070 }
0071 
0072 static int isl6405_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
0073 {
0074     struct isl6405 *isl6405 = (struct isl6405 *) fe->sec_priv;
0075     struct i2c_msg msg = {  .addr = isl6405->i2c_addr, .flags = 0,
0076                 .buf = &isl6405->config,
0077                 .len = sizeof(isl6405->config) };
0078 
0079     if (isl6405->override_or & 0x80) {
0080         if (arg)
0081             isl6405->config |= ISL6405_LLC2;
0082         else
0083             isl6405->config &= ~ISL6405_LLC2;
0084     } else {
0085         if (arg)
0086             isl6405->config |= ISL6405_LLC1;
0087         else
0088             isl6405->config &= ~ISL6405_LLC1;
0089     }
0090     isl6405->config |= isl6405->override_or;
0091     isl6405->config &= isl6405->override_and;
0092 
0093     return (i2c_transfer(isl6405->i2c, &msg, 1) == 1) ? 0 : -EIO;
0094 }
0095 
0096 static void isl6405_release(struct dvb_frontend *fe)
0097 {
0098     /* power off */
0099     isl6405_set_voltage(fe, SEC_VOLTAGE_OFF);
0100 
0101     /* free */
0102     kfree(fe->sec_priv);
0103     fe->sec_priv = NULL;
0104 }
0105 
0106 struct dvb_frontend *isl6405_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c,
0107                     u8 i2c_addr, u8 override_set, u8 override_clear)
0108 {
0109     struct isl6405 *isl6405 = kmalloc(sizeof(struct isl6405), GFP_KERNEL);
0110     if (!isl6405)
0111         return NULL;
0112 
0113     /* default configuration */
0114     if (override_set & 0x80)
0115         isl6405->config = ISL6405_ISEL2;
0116     else
0117         isl6405->config = ISL6405_ISEL1;
0118     isl6405->i2c = i2c;
0119     isl6405->i2c_addr = i2c_addr;
0120     fe->sec_priv = isl6405;
0121 
0122     /* bits which should be forced to '1' */
0123     isl6405->override_or = override_set;
0124 
0125     /* bits which should be forced to '0' */
0126     isl6405->override_and = ~override_clear;
0127 
0128     /* detect if it is present or not */
0129     if (isl6405_set_voltage(fe, SEC_VOLTAGE_OFF)) {
0130         kfree(isl6405);
0131         fe->sec_priv = NULL;
0132         return NULL;
0133     }
0134 
0135     /* install release callback */
0136     fe->ops.release_sec = isl6405_release;
0137 
0138     /* override frontend ops */
0139     fe->ops.set_voltage = isl6405_set_voltage;
0140     fe->ops.enable_high_lnb_voltage = isl6405_enable_high_lnb_voltage;
0141 
0142     return fe;
0143 }
0144 EXPORT_SYMBOL(isl6405_attach);
0145 
0146 MODULE_DESCRIPTION("Driver for lnb supply and control ic isl6405");
0147 MODULE_AUTHOR("Hartmut Hackmann & Oliver Endriss");
0148 MODULE_LICENSE("GPL");