149 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * isl6405.c - driver for dual lnb supply and control ic ISL64054 *5 * Copyright (C) 2008 Hartmut Hackmann6 * Copyright (C) 2006 Oliver Endriss7 *8 * the project's page is at https://linuxtv.org9 */10#include <linux/delay.h>11#include <linux/errno.h>12#include <linux/init.h>13#include <linux/kernel.h>14#include <linux/module.h>15#include <linux/string.h>16#include <linux/slab.h>17 18#include <media/dvb_frontend.h>19#include "isl6405.h"20 21struct isl6405 {22 u8 config;23 u8 override_or;24 u8 override_and;25 struct i2c_adapter *i2c;26 u8 i2c_addr;27};28 29static int isl6405_set_voltage(struct dvb_frontend *fe,30 enum fe_sec_voltage voltage)31{32 struct isl6405 *isl6405 = (struct isl6405 *) fe->sec_priv;33 struct i2c_msg msg = { .addr = isl6405->i2c_addr, .flags = 0,34 .buf = &isl6405->config,35 .len = sizeof(isl6405->config) };36 37 if (isl6405->override_or & 0x80) {38 isl6405->config &= ~(ISL6405_VSEL2 | ISL6405_EN2);39 switch (voltage) {40 case SEC_VOLTAGE_OFF:41 break;42 case SEC_VOLTAGE_13:43 isl6405->config |= ISL6405_EN2;44 break;45 case SEC_VOLTAGE_18:46 isl6405->config |= (ISL6405_EN2 | ISL6405_VSEL2);47 break;48 default:49 return -EINVAL;50 }51 } else {52 isl6405->config &= ~(ISL6405_VSEL1 | ISL6405_EN1);53 switch (voltage) {54 case SEC_VOLTAGE_OFF:55 break;56 case SEC_VOLTAGE_13:57 isl6405->config |= ISL6405_EN1;58 break;59 case SEC_VOLTAGE_18:60 isl6405->config |= (ISL6405_EN1 | ISL6405_VSEL1);61 break;62 default:63 return -EINVAL;64 }65 }66 isl6405->config |= isl6405->override_or;67 isl6405->config &= isl6405->override_and;68 69 return (i2c_transfer(isl6405->i2c, &msg, 1) == 1) ? 0 : -EIO;70}71 72static int isl6405_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)73{74 struct isl6405 *isl6405 = (struct isl6405 *) fe->sec_priv;75 struct i2c_msg msg = { .addr = isl6405->i2c_addr, .flags = 0,76 .buf = &isl6405->config,77 .len = sizeof(isl6405->config) };78 79 if (isl6405->override_or & 0x80) {80 if (arg)81 isl6405->config |= ISL6405_LLC2;82 else83 isl6405->config &= ~ISL6405_LLC2;84 } else {85 if (arg)86 isl6405->config |= ISL6405_LLC1;87 else88 isl6405->config &= ~ISL6405_LLC1;89 }90 isl6405->config |= isl6405->override_or;91 isl6405->config &= isl6405->override_and;92 93 return (i2c_transfer(isl6405->i2c, &msg, 1) == 1) ? 0 : -EIO;94}95 96static void isl6405_release(struct dvb_frontend *fe)97{98 /* power off */99 isl6405_set_voltage(fe, SEC_VOLTAGE_OFF);100 101 /* free */102 kfree(fe->sec_priv);103 fe->sec_priv = NULL;104}105 106struct dvb_frontend *isl6405_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c,107 u8 i2c_addr, u8 override_set, u8 override_clear)108{109 struct isl6405 *isl6405 = kmalloc(sizeof(struct isl6405), GFP_KERNEL);110 if (!isl6405)111 return NULL;112 113 /* default configuration */114 if (override_set & 0x80)115 isl6405->config = ISL6405_ISEL2;116 else117 isl6405->config = ISL6405_ISEL1;118 isl6405->i2c = i2c;119 isl6405->i2c_addr = i2c_addr;120 fe->sec_priv = isl6405;121 122 /* bits which should be forced to '1' */123 isl6405->override_or = override_set;124 125 /* bits which should be forced to '0' */126 isl6405->override_and = ~override_clear;127 128 /* detect if it is present or not */129 if (isl6405_set_voltage(fe, SEC_VOLTAGE_OFF)) {130 kfree(isl6405);131 fe->sec_priv = NULL;132 return NULL;133 }134 135 /* install release callback */136 fe->ops.release_sec = isl6405_release;137 138 /* override frontend ops */139 fe->ops.set_voltage = isl6405_set_voltage;140 fe->ops.enable_high_lnb_voltage = isl6405_enable_high_lnb_voltage;141 142 return fe;143}144EXPORT_SYMBOL_GPL(isl6405_attach);145 146MODULE_DESCRIPTION("Driver for lnb supply and control ic isl6405");147MODULE_AUTHOR("Hartmut Hackmann & Oliver Endriss");148MODULE_LICENSE("GPL");149