linux/drivers/media/dvb-frontends/lnbp21.c
<<
>>
Prefs
   1/*
   2 * lnbp21.c - driver for lnb supply and control ic lnbp21
   3 *
   4 * Copyright (C) 2006, 2009 Oliver Endriss <o.endriss@gmx.de>
   5 * Copyright (C) 2009 Igor M. Liplianin <liplianin@netup.ru>
   6 *
   7 * This program is free software; you can redistribute it and/or
   8 * modify it under the terms of the GNU General Public License
   9 * as published by the Free Software Foundation; either version 2
  10 * of the License, or (at your option) any later version.
  11 *
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 *
  18 *
  19 * You should have received a copy of the GNU General Public License
  20 * along with this program; if not, write to the Free Software
  21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  22 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
  23 *
  24 *
  25 * the project's page is at http://www.linuxtv.org
  26 */
  27#include <linux/delay.h>
  28#include <linux/errno.h>
  29#include <linux/init.h>
  30#include <linux/kernel.h>
  31#include <linux/module.h>
  32#include <linux/string.h>
  33#include <linux/slab.h>
  34
  35#include "dvb_frontend.h"
  36#include "lnbp21.h"
  37#include "lnbh24.h"
  38
  39struct lnbp21 {
  40        u8                      config;
  41        u8                      override_or;
  42        u8                      override_and;
  43        struct i2c_adapter      *i2c;
  44        u8                      i2c_addr;
  45};
  46
  47static int lnbp21_set_voltage(struct dvb_frontend *fe,
  48                                        fe_sec_voltage_t voltage)
  49{
  50        struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv;
  51        struct i2c_msg msg = {  .addr = lnbp21->i2c_addr, .flags = 0,
  52                                .buf = &lnbp21->config,
  53                                .len = sizeof(lnbp21->config) };
  54
  55        lnbp21->config &= ~(LNBP21_VSEL | LNBP21_EN);
  56
  57        switch(voltage) {
  58        case SEC_VOLTAGE_OFF:
  59                break;
  60        case SEC_VOLTAGE_13:
  61                lnbp21->config |= LNBP21_EN;
  62                break;
  63        case SEC_VOLTAGE_18:
  64                lnbp21->config |= (LNBP21_EN | LNBP21_VSEL);
  65                break;
  66        default:
  67                return -EINVAL;
  68        }
  69
  70        lnbp21->config |= lnbp21->override_or;
  71        lnbp21->config &= lnbp21->override_and;
  72
  73        return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
  74}
  75
  76static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
  77{
  78        struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv;
  79        struct i2c_msg msg = {  .addr = lnbp21->i2c_addr, .flags = 0,
  80                                .buf = &lnbp21->config,
  81                                .len = sizeof(lnbp21->config) };
  82
  83        if (arg)
  84                lnbp21->config |= LNBP21_LLC;
  85        else
  86                lnbp21->config &= ~LNBP21_LLC;
  87
  88        lnbp21->config |= lnbp21->override_or;
  89        lnbp21->config &= lnbp21->override_and;
  90
  91        return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
  92}
  93
  94static int lnbp21_set_tone(struct dvb_frontend *fe,
  95                                fe_sec_tone_mode_t tone)
  96{
  97        struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->sec_priv;
  98        struct i2c_msg msg = {  .addr = lnbp21->i2c_addr, .flags = 0,
  99                                .buf = &lnbp21->config,
 100                                .len = sizeof(lnbp21->config) };
 101
 102        switch (tone) {
 103        case SEC_TONE_OFF:
 104                lnbp21->config &= ~LNBP21_TEN;
 105                break;
 106        case SEC_TONE_ON:
 107                lnbp21->config |= LNBP21_TEN;
 108                break;
 109        default:
 110                return -EINVAL;
 111        }
 112
 113        lnbp21->config |= lnbp21->override_or;
 114        lnbp21->config &= lnbp21->override_and;
 115
 116        return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO;
 117}
 118
 119static void lnbp21_release(struct dvb_frontend *fe)
 120{
 121        /* LNBP power off */
 122        lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF);
 123
 124        /* free data */
 125        kfree(fe->sec_priv);
 126        fe->sec_priv = NULL;
 127}
 128
 129static struct dvb_frontend *lnbx2x_attach(struct dvb_frontend *fe,
 130                                struct i2c_adapter *i2c, u8 override_set,
 131                                u8 override_clear, u8 i2c_addr, u8 config)
 132{
 133        struct lnbp21 *lnbp21 = kmalloc(sizeof(struct lnbp21), GFP_KERNEL);
 134        if (!lnbp21)
 135                return NULL;
 136
 137        /* default configuration */
 138        lnbp21->config = config;
 139        lnbp21->i2c = i2c;
 140        lnbp21->i2c_addr = i2c_addr;
 141        fe->sec_priv = lnbp21;
 142
 143        /* bits which should be forced to '1' */
 144        lnbp21->override_or = override_set;
 145
 146        /* bits which should be forced to '0' */
 147        lnbp21->override_and = ~override_clear;
 148
 149        /* detect if it is present or not */
 150        if (lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF)) {
 151                kfree(lnbp21);
 152                return NULL;
 153        }
 154
 155        /* install release callback */
 156        fe->ops.release_sec = lnbp21_release;
 157
 158        /* override frontend ops */
 159        fe->ops.set_voltage = lnbp21_set_voltage;
 160        fe->ops.enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
 161        if (!(override_clear & LNBH24_TEN)) /*22kHz logic controlled by demod*/
 162                fe->ops.set_tone = lnbp21_set_tone;
 163        printk(KERN_INFO "LNBx2x attached on addr=%x\n", lnbp21->i2c_addr);
 164
 165        return fe;
 166}
 167
 168struct dvb_frontend *lnbh24_attach(struct dvb_frontend *fe,
 169                                struct i2c_adapter *i2c, u8 override_set,
 170                                u8 override_clear, u8 i2c_addr)
 171{
 172        return lnbx2x_attach(fe, i2c, override_set, override_clear,
 173                                                        i2c_addr, LNBH24_TTX);
 174}
 175EXPORT_SYMBOL(lnbh24_attach);
 176
 177struct dvb_frontend *lnbp21_attach(struct dvb_frontend *fe,
 178                                struct i2c_adapter *i2c, u8 override_set,
 179                                u8 override_clear)
 180{
 181        return lnbx2x_attach(fe, i2c, override_set, override_clear,
 182                                                        0x08, LNBP21_ISEL);
 183}
 184EXPORT_SYMBOL(lnbp21_attach);
 185
 186MODULE_DESCRIPTION("Driver for lnb supply and control ic lnbp21, lnbh24");
 187MODULE_AUTHOR("Oliver Endriss, Igor M. Liplianin");
 188MODULE_LICENSE("GPL");
 189