linux/drivers/media/dvb-frontends/isl6423.c
<<
>>
Prefs
   1/*
   2        Intersil ISL6423 SEC and LNB Power supply controller
   3
   4        Copyright (C) Manu Abraham <abraham.manu@gmail.com>
   5
   6        This program is free software; you can redistribute it and/or modify
   7        it under the terms of the GNU General Public License as published by
   8        the Free Software Foundation; either version 2 of the License, or
   9        (at your option) any later version.
  10
  11        This program is distributed in the hope that it will be useful,
  12        but WITHOUT ANY WARRANTY; without even the implied warranty of
  13        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14        GNU General Public License for more details.
  15
  16        You should have received a copy of the GNU General Public License
  17        along with this program; if not, write to the Free Software
  18        Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19*/
  20
  21#include <linux/delay.h>
  22#include <linux/errno.h>
  23#include <linux/init.h>
  24#include <linux/kernel.h>
  25#include <linux/module.h>
  26#include <linux/string.h>
  27#include <linux/slab.h>
  28
  29#include "dvb_frontend.h"
  30#include "isl6423.h"
  31
  32static unsigned int verbose;
  33module_param(verbose, int, 0644);
  34MODULE_PARM_DESC(verbose, "Set Verbosity level");
  35
  36#define FE_ERROR                                0
  37#define FE_NOTICE                               1
  38#define FE_INFO                                 2
  39#define FE_DEBUG                                3
  40#define FE_DEBUGREG                             4
  41
  42#define dprintk(__y, __z, format, arg...) do {                                          \
  43        if (__z) {                                                                      \
  44                if      ((verbose > FE_ERROR) && (verbose > __y))                       \
  45                        printk(KERN_ERR "%s: " format "\n", __func__ , ##arg);          \
  46                else if ((verbose > FE_NOTICE) && (verbose > __y))                      \
  47                        printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg);       \
  48                else if ((verbose > FE_INFO) && (verbose > __y))                        \
  49                        printk(KERN_INFO "%s: " format "\n", __func__ , ##arg);         \
  50                else if ((verbose > FE_DEBUG) && (verbose > __y))                       \
  51                        printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg);        \
  52        } else {                                                                        \
  53                if (verbose > __y)                                                      \
  54                        printk(format, ##arg);                                          \
  55        }                                                                               \
  56} while (0)
  57
  58struct isl6423_dev {
  59        const struct isl6423_config     *config;
  60        struct i2c_adapter              *i2c;
  61
  62        u8 reg_3;
  63        u8 reg_4;
  64
  65        unsigned int verbose;
  66};
  67
  68static int isl6423_write(struct isl6423_dev *isl6423, u8 reg)
  69{
  70        struct i2c_adapter *i2c = isl6423->i2c;
  71        u8 addr                 = isl6423->config->addr;
  72        int err = 0;
  73
  74        struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = &reg, .len = 1 };
  75
  76        dprintk(FE_DEBUG, 1, "write reg %02X", reg);
  77        err = i2c_transfer(i2c, &msg, 1);
  78        if (err < 0)
  79                goto exit;
  80        return 0;
  81
  82exit:
  83        dprintk(FE_ERROR, 1, "I/O error <%d>", err);
  84        return err;
  85}
  86
  87static int isl6423_set_modulation(struct dvb_frontend *fe)
  88{
  89        struct isl6423_dev *isl6423             = (struct isl6423_dev *) fe->sec_priv;
  90        const struct isl6423_config *config     = isl6423->config;
  91        int err = 0;
  92        u8 reg_2 = 0;
  93
  94        reg_2 = 0x01 << 5;
  95
  96        if (config->mod_extern)
  97                reg_2 |= (1 << 3);
  98        else
  99                reg_2 |= (1 << 4);
 100
 101        err = isl6423_write(isl6423, reg_2);
 102        if (err < 0)
 103                goto exit;
 104        return 0;
 105
 106exit:
 107        dprintk(FE_ERROR, 1, "I/O error <%d>", err);
 108        return err;
 109}
 110
 111static int isl6423_voltage_boost(struct dvb_frontend *fe, long arg)
 112{
 113        struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv;
 114        u8 reg_3 = isl6423->reg_3;
 115        u8 reg_4 = isl6423->reg_4;
 116        int err = 0;
 117
 118        if (arg) {
 119                /* EN = 1, VSPEN = 1, VBOT = 1 */
 120                reg_4 |= (1 << 4);
 121                reg_4 |= 0x1;
 122                reg_3 |= (1 << 3);
 123        } else {
 124                /* EN = 1, VSPEN = 1, VBOT = 0 */
 125                reg_4 |= (1 << 4);
 126                reg_4 &= ~0x1;
 127                reg_3 |= (1 << 3);
 128        }
 129        err = isl6423_write(isl6423, reg_3);
 130        if (err < 0)
 131                goto exit;
 132
 133        err = isl6423_write(isl6423, reg_4);
 134        if (err < 0)
 135                goto exit;
 136
 137        isl6423->reg_3 = reg_3;
 138        isl6423->reg_4 = reg_4;
 139
 140        return 0;
 141exit:
 142        dprintk(FE_ERROR, 1, "I/O error <%d>", err);
 143        return err;
 144}
 145
 146
 147static int isl6423_set_voltage(struct dvb_frontend *fe,
 148                               enum fe_sec_voltage voltage)
 149{
 150        struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv;
 151        u8 reg_3 = isl6423->reg_3;
 152        u8 reg_4 = isl6423->reg_4;
 153        int err = 0;
 154
 155        switch (voltage) {
 156        case SEC_VOLTAGE_OFF:
 157                /* EN = 0 */
 158                reg_4 &= ~(1 << 4);
 159                break;
 160
 161        case SEC_VOLTAGE_13:
 162                /* EN = 1, VSPEN = 1, VTOP = 0, VBOT = 0 */
 163                reg_4 |= (1 << 4);
 164                reg_4 &= ~0x3;
 165                reg_3 |= (1 << 3);
 166                break;
 167
 168        case SEC_VOLTAGE_18:
 169                /* EN = 1, VSPEN = 1, VTOP = 1, VBOT = 0 */
 170                reg_4 |= (1 << 4);
 171                reg_4 |=  0x2;
 172                reg_4 &= ~0x1;
 173                reg_3 |= (1 << 3);
 174                break;
 175
 176        default:
 177                break;
 178        }
 179        err = isl6423_write(isl6423, reg_3);
 180        if (err < 0)
 181                goto exit;
 182
 183        err = isl6423_write(isl6423, reg_4);
 184        if (err < 0)
 185                goto exit;
 186
 187        isl6423->reg_3 = reg_3;
 188        isl6423->reg_4 = reg_4;
 189
 190        return 0;
 191exit:
 192        dprintk(FE_ERROR, 1, "I/O error <%d>", err);
 193        return err;
 194}
 195
 196static int isl6423_set_current(struct dvb_frontend *fe)
 197{
 198        struct isl6423_dev *isl6423             = (struct isl6423_dev *) fe->sec_priv;
 199        u8 reg_3 = isl6423->reg_3;
 200        const struct isl6423_config *config     = isl6423->config;
 201        int err = 0;
 202
 203        switch (config->current_max) {
 204        case SEC_CURRENT_275m:
 205                /* 275mA */
 206                /* ISELH = 0, ISELL = 0 */
 207                reg_3 &= ~0x3;
 208                break;
 209
 210        case SEC_CURRENT_515m:
 211                /* 515mA */
 212                /* ISELH = 0, ISELL = 1 */
 213                reg_3 &= ~0x2;
 214                reg_3 |=  0x1;
 215                break;
 216
 217        case SEC_CURRENT_635m:
 218                /* 635mA */
 219                /* ISELH = 1, ISELL = 0 */
 220                reg_3 &= ~0x1;
 221                reg_3 |=  0x2;
 222                break;
 223
 224        case SEC_CURRENT_800m:
 225                /* 800mA */
 226                /* ISELH = 1, ISELL = 1 */
 227                reg_3 |= 0x3;
 228                break;
 229        }
 230
 231        err = isl6423_write(isl6423, reg_3);
 232        if (err < 0)
 233                goto exit;
 234
 235        switch (config->curlim) {
 236        case SEC_CURRENT_LIM_ON:
 237                /* DCL = 0 */
 238                reg_3 &= ~0x10;
 239                break;
 240
 241        case SEC_CURRENT_LIM_OFF:
 242                /* DCL = 1 */
 243                reg_3 |= 0x10;
 244                break;
 245        }
 246
 247        err = isl6423_write(isl6423, reg_3);
 248        if (err < 0)
 249                goto exit;
 250
 251        isl6423->reg_3 = reg_3;
 252
 253        return 0;
 254exit:
 255        dprintk(FE_ERROR, 1, "I/O error <%d>", err);
 256        return err;
 257}
 258
 259static void isl6423_release(struct dvb_frontend *fe)
 260{
 261        isl6423_set_voltage(fe, SEC_VOLTAGE_OFF);
 262
 263        kfree(fe->sec_priv);
 264        fe->sec_priv = NULL;
 265}
 266
 267struct dvb_frontend *isl6423_attach(struct dvb_frontend *fe,
 268                                    struct i2c_adapter *i2c,
 269                                    const struct isl6423_config *config)
 270{
 271        struct isl6423_dev *isl6423;
 272
 273        isl6423 = kzalloc(sizeof(struct isl6423_dev), GFP_KERNEL);
 274        if (!isl6423)
 275                return NULL;
 276
 277        isl6423->config = config;
 278        isl6423->i2c    = i2c;
 279        fe->sec_priv    = isl6423;
 280
 281        /* SR3H = 0, SR3M = 1, SR3L = 0 */
 282        isl6423->reg_3 = 0x02 << 5;
 283        /* SR4H = 0, SR4M = 1, SR4L = 1 */
 284        isl6423->reg_4 = 0x03 << 5;
 285
 286        if (isl6423_set_current(fe))
 287                goto exit;
 288
 289        if (isl6423_set_modulation(fe))
 290                goto exit;
 291
 292        fe->ops.release_sec             = isl6423_release;
 293        fe->ops.set_voltage             = isl6423_set_voltage;
 294        fe->ops.enable_high_lnb_voltage = isl6423_voltage_boost;
 295        isl6423->verbose                = verbose;
 296
 297        return fe;
 298
 299exit:
 300        kfree(isl6423);
 301        fe->sec_priv = NULL;
 302        return NULL;
 303}
 304EXPORT_SYMBOL(isl6423_attach);
 305
 306MODULE_DESCRIPTION("ISL6423 SEC");
 307MODULE_AUTHOR("Manu Abraham");
 308MODULE_LICENSE("GPL");
 309