linux/drivers/media/dvb-frontends/horus3a.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * horus3a.h
   4 *
   5 * Sony Horus3A DVB-S/S2 tuner driver
   6 *
   7 * Copyright 2012 Sony Corporation
   8 * Copyright (C) 2014 NetUP Inc.
   9 * Copyright (C) 2014 Sergey Kozlov <serjk@netup.ru>
  10 * Copyright (C) 2014 Abylay Ospan <aospan@netup.ru>
  11 */
  12
  13#include <linux/slab.h>
  14#include <linux/module.h>
  15#include <linux/dvb/frontend.h>
  16#include <linux/types.h>
  17#include "horus3a.h"
  18#include <media/dvb_frontend.h>
  19
  20#define MAX_WRITE_REGSIZE      5
  21
  22enum horus3a_state {
  23        STATE_UNKNOWN,
  24        STATE_SLEEP,
  25        STATE_ACTIVE
  26};
  27
  28struct horus3a_priv {
  29        u32                     frequency;
  30        u8                      i2c_address;
  31        struct i2c_adapter      *i2c;
  32        enum horus3a_state      state;
  33        void                    *set_tuner_data;
  34        int                     (*set_tuner)(void *, int);
  35};
  36
  37static void horus3a_i2c_debug(struct horus3a_priv *priv,
  38                              u8 reg, u8 write, const u8 *data, u32 len)
  39{
  40        dev_dbg(&priv->i2c->dev, "horus3a: I2C %s reg 0x%02x size %d\n",
  41                (write == 0 ? "read" : "write"), reg, len);
  42        print_hex_dump_bytes("horus3a: I2C data: ",
  43                DUMP_PREFIX_OFFSET, data, len);
  44}
  45
  46static int horus3a_write_regs(struct horus3a_priv *priv,
  47                              u8 reg, const u8 *data, u32 len)
  48{
  49        int ret;
  50        u8 buf[MAX_WRITE_REGSIZE + 1];
  51        struct i2c_msg msg[1] = {
  52                {
  53                        .addr = priv->i2c_address,
  54                        .flags = 0,
  55                        .len = len + 1,
  56                        .buf = buf,
  57                }
  58        };
  59
  60        if (len + 1 > sizeof(buf)) {
  61                dev_warn(&priv->i2c->dev,"wr reg=%04x: len=%d is too big!\n",
  62                         reg, len + 1);
  63                return -E2BIG;
  64        }
  65
  66        horus3a_i2c_debug(priv, reg, 1, data, len);
  67        buf[0] = reg;
  68        memcpy(&buf[1], data, len);
  69        ret = i2c_transfer(priv->i2c, msg, 1);
  70        if (ret >= 0 && ret != 1)
  71                ret = -EREMOTEIO;
  72        if (ret < 0) {
  73                dev_warn(&priv->i2c->dev,
  74                        "%s: i2c wr failed=%d reg=%02x len=%d\n",
  75                        KBUILD_MODNAME, ret, reg, len);
  76                return ret;
  77        }
  78        return 0;
  79}
  80
  81static int horus3a_write_reg(struct horus3a_priv *priv, u8 reg, u8 val)
  82{
  83        u8 tmp = val; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
  84
  85        return horus3a_write_regs(priv, reg, &tmp, 1);
  86}
  87
  88static int horus3a_enter_power_save(struct horus3a_priv *priv)
  89{
  90        u8 data[2];
  91
  92        dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
  93        if (priv->state == STATE_SLEEP)
  94                return 0;
  95        /* IQ Generator disable */
  96        horus3a_write_reg(priv, 0x2a, 0x79);
  97        /* MDIV_EN = 0 */
  98        horus3a_write_reg(priv, 0x29, 0x70);
  99        /* VCO disable preparation */
 100        horus3a_write_reg(priv, 0x28, 0x3e);
 101        /* VCO buffer disable */
 102        horus3a_write_reg(priv, 0x2a, 0x19);
 103        /* VCO calibration disable */
 104        horus3a_write_reg(priv, 0x1c, 0x00);
 105        /* Power save setting (xtal is not stopped) */
 106        data[0] = 0xC0;
 107        /* LNA is Disabled */
 108        data[1] = 0xA7;
 109        /* 0x11 - 0x12 */
 110        horus3a_write_regs(priv, 0x11, data, sizeof(data));
 111        priv->state = STATE_SLEEP;
 112        return 0;
 113}
 114
 115static int horus3a_leave_power_save(struct horus3a_priv *priv)
 116{
 117        u8 data[2];
 118
 119        dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
 120        if (priv->state == STATE_ACTIVE)
 121                return 0;
 122        /* Leave power save */
 123        data[0] = 0x00;
 124        /* LNA is Disabled */
 125        data[1] = 0xa7;
 126        /* 0x11 - 0x12 */
 127        horus3a_write_regs(priv, 0x11, data, sizeof(data));
 128        /* VCO buffer enable */
 129        horus3a_write_reg(priv, 0x2a, 0x79);
 130        /* VCO calibration enable */
 131        horus3a_write_reg(priv, 0x1c, 0xc0);
 132        /* MDIV_EN = 1 */
 133        horus3a_write_reg(priv, 0x29, 0x71);
 134        usleep_range(5000, 7000);
 135        priv->state = STATE_ACTIVE;
 136        return 0;
 137}
 138
 139static int horus3a_init(struct dvb_frontend *fe)
 140{
 141        struct horus3a_priv *priv = fe->tuner_priv;
 142
 143        dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
 144        return 0;
 145}
 146
 147static void horus3a_release(struct dvb_frontend *fe)
 148{
 149        struct horus3a_priv *priv = fe->tuner_priv;
 150
 151        dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
 152        kfree(fe->tuner_priv);
 153        fe->tuner_priv = NULL;
 154}
 155
 156static int horus3a_sleep(struct dvb_frontend *fe)
 157{
 158        struct horus3a_priv *priv = fe->tuner_priv;
 159
 160        dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
 161        horus3a_enter_power_save(priv);
 162        return 0;
 163}
 164
 165static int horus3a_set_params(struct dvb_frontend *fe)
 166{
 167        struct dtv_frontend_properties *p = &fe->dtv_property_cache;
 168        struct horus3a_priv *priv = fe->tuner_priv;
 169        u32 frequency = p->frequency;
 170        u32 symbol_rate = p->symbol_rate/1000;
 171        u8 mixdiv = 0;
 172        u8 mdiv = 0;
 173        u32 ms = 0;
 174        u8 f_ctl = 0;
 175        u8 g_ctl = 0;
 176        u8 fc_lpf = 0;
 177        u8 data[5];
 178
 179        dev_dbg(&priv->i2c->dev, "%s(): frequency %dkHz symbol_rate %dksps\n",
 180                __func__, frequency, symbol_rate);
 181        if (priv->set_tuner)
 182                priv->set_tuner(priv->set_tuner_data, 0);
 183        if (priv->state == STATE_SLEEP)
 184                horus3a_leave_power_save(priv);
 185
 186        /* frequency should be X MHz (X : integer) */
 187        frequency = DIV_ROUND_CLOSEST(frequency, 1000) * 1000;
 188        if (frequency <= 1155000) {
 189                mixdiv = 4;
 190                mdiv = 1;
 191        } else {
 192                mixdiv = 2;
 193                mdiv = 0;
 194        }
 195        /* Assumed that fREF == 1MHz (1000kHz) */
 196        ms = DIV_ROUND_CLOSEST((frequency * mixdiv) / 2, 1000);
 197        if (ms > 0x7FFF) { /* 15 bit */
 198                dev_err(&priv->i2c->dev, "horus3a: invalid frequency %d\n",
 199                        frequency);
 200                return -EINVAL;
 201        }
 202        if (frequency < 975000) {
 203                /* F_CTL=11100 G_CTL=001 */
 204                f_ctl = 0x1C;
 205                g_ctl = 0x01;
 206        } else if (frequency < 1050000) {
 207                /* F_CTL=11000 G_CTL=010 */
 208                f_ctl = 0x18;
 209                g_ctl = 0x02;
 210        } else if (frequency < 1150000) {
 211                /* F_CTL=10100 G_CTL=010 */
 212                f_ctl = 0x14;
 213                g_ctl = 0x02;
 214        } else if (frequency < 1250000) {
 215                /* F_CTL=10000 G_CTL=011 */
 216                f_ctl = 0x10;
 217                g_ctl = 0x03;
 218        } else if (frequency < 1350000) {
 219                /* F_CTL=01100 G_CTL=100 */
 220                f_ctl = 0x0C;
 221                g_ctl = 0x04;
 222        } else if (frequency < 1450000) {
 223                /* F_CTL=01010 G_CTL=100 */
 224                f_ctl = 0x0A;
 225                g_ctl = 0x04;
 226        } else if (frequency < 1600000) {
 227                /* F_CTL=00111 G_CTL=101 */
 228                f_ctl = 0x07;
 229                g_ctl = 0x05;
 230        } else if (frequency < 1800000) {
 231                /* F_CTL=00100 G_CTL=010 */
 232                f_ctl = 0x04;
 233                g_ctl = 0x02;
 234        } else if (frequency < 2000000) {
 235                /* F_CTL=00010 G_CTL=001 */
 236                f_ctl = 0x02;
 237                g_ctl = 0x01;
 238        } else {
 239                /* F_CTL=00000 G_CTL=000 */
 240                f_ctl = 0x00;
 241                g_ctl = 0x00;
 242        }
 243        /* LPF cutoff frequency setting */
 244        if (p->delivery_system == SYS_DVBS) {
 245                /*
 246                 * rolloff = 0.35
 247                 * SR <= 4.3
 248                 * fc_lpf = 5
 249                 * 4.3 < SR <= 10
 250                 * fc_lpf = SR * (1 + rolloff) / 2 + SR / 2 =
 251                 *      SR * 1.175 = SR * (47/40)
 252                 * 10 < SR
 253                 * fc_lpf = SR * (1 + rolloff) / 2 + 5 =
 254                 *      SR * 0.675 + 5 = SR * (27/40) + 5
 255                 * NOTE: The result should be round up.
 256                 */
 257                if (symbol_rate <= 4300)
 258                        fc_lpf = 5;
 259                else if (symbol_rate <= 10000)
 260                        fc_lpf = (u8)DIV_ROUND_UP(symbol_rate * 47, 40000);
 261                else
 262                        fc_lpf = (u8)DIV_ROUND_UP(symbol_rate * 27, 40000) + 5;
 263                /* 5 <= fc_lpf <= 36 */
 264                if (fc_lpf > 36)
 265                        fc_lpf = 36;
 266        } else if (p->delivery_system == SYS_DVBS2) {
 267                /*
 268                 * SR <= 4.5:
 269                 * fc_lpf = 5
 270                 * 4.5 < SR <= 10:
 271                 * fc_lpf = SR * (1 + rolloff) / 2 + SR / 2
 272                 * 10 < SR:
 273                 * fc_lpf = SR * (1 + rolloff) / 2 + 5
 274                 * NOTE: The result should be round up.
 275                 */
 276                if (symbol_rate <= 4500)
 277                        fc_lpf = 5;
 278                else if (symbol_rate <= 10000)
 279                        fc_lpf = (u8)((symbol_rate * 11 + (10000-1)) / 10000);
 280                else
 281                        fc_lpf = (u8)((symbol_rate * 3 + (5000-1)) / 5000 + 5);
 282                /* 5 <= fc_lpf <= 36 is valid */
 283                if (fc_lpf > 36)
 284                        fc_lpf = 36;
 285        } else {
 286                dev_err(&priv->i2c->dev,
 287                        "horus3a: invalid delivery system %d\n",
 288                        p->delivery_system);
 289                return -EINVAL;
 290        }
 291        /* 0x00 - 0x04 */
 292        data[0] = (u8)((ms >> 7) & 0xFF);
 293        data[1] = (u8)((ms << 1) & 0xFF);
 294        data[2] = 0x00;
 295        data[3] = 0x00;
 296        data[4] = (u8)(mdiv << 7);
 297        horus3a_write_regs(priv, 0x00, data, sizeof(data));
 298        /* Write G_CTL, F_CTL */
 299        horus3a_write_reg(priv, 0x09, (u8)((g_ctl << 5) | f_ctl));
 300        /* Write LPF cutoff frequency */
 301        horus3a_write_reg(priv, 0x37, (u8)(0x80 | (fc_lpf << 1)));
 302        /* Start Calibration */
 303        horus3a_write_reg(priv, 0x05, 0x80);
 304        /* IQ Generator enable */
 305        horus3a_write_reg(priv, 0x2a, 0x7b);
 306        /* tuner stabilization time */
 307        msleep(60);
 308        /* Store tuned frequency to the struct */
 309        priv->frequency = ms * 2 * 1000 / mixdiv;
 310        return 0;
 311}
 312
 313static int horus3a_get_frequency(struct dvb_frontend *fe, u32 *frequency)
 314{
 315        struct horus3a_priv *priv = fe->tuner_priv;
 316
 317        *frequency = priv->frequency;
 318        return 0;
 319}
 320
 321static const struct dvb_tuner_ops horus3a_tuner_ops = {
 322        .info = {
 323                .name = "Sony Horus3a",
 324                .frequency_min_hz  =  950 * MHz,
 325                .frequency_max_hz  = 2150 * MHz,
 326                .frequency_step_hz =    1 * MHz,
 327        },
 328        .init = horus3a_init,
 329        .release = horus3a_release,
 330        .sleep = horus3a_sleep,
 331        .set_params = horus3a_set_params,
 332        .get_frequency = horus3a_get_frequency,
 333};
 334
 335struct dvb_frontend *horus3a_attach(struct dvb_frontend *fe,
 336                                    const struct horus3a_config *config,
 337                                    struct i2c_adapter *i2c)
 338{
 339        u8 buf[3], val;
 340        struct horus3a_priv *priv = NULL;
 341
 342        priv = kzalloc(sizeof(struct horus3a_priv), GFP_KERNEL);
 343        if (priv == NULL)
 344                return NULL;
 345        priv->i2c_address = (config->i2c_address >> 1);
 346        priv->i2c = i2c;
 347        priv->set_tuner_data = config->set_tuner_priv;
 348        priv->set_tuner = config->set_tuner_callback;
 349
 350        if (fe->ops.i2c_gate_ctrl)
 351                fe->ops.i2c_gate_ctrl(fe, 1);
 352
 353        /* wait 4ms after power on */
 354        usleep_range(4000, 6000);
 355        /* IQ Generator disable */
 356        horus3a_write_reg(priv, 0x2a, 0x79);
 357        /* REF_R = Xtal Frequency */
 358        buf[0] = config->xtal_freq_mhz;
 359        buf[1] = config->xtal_freq_mhz;
 360        buf[2] = 0;
 361        /* 0x6 - 0x8 */
 362        horus3a_write_regs(priv, 0x6, buf, 3);
 363        /* IQ Out = Single Ended */
 364        horus3a_write_reg(priv, 0x0a, 0x40);
 365        switch (config->xtal_freq_mhz) {
 366        case 27:
 367                val = 0x1f;
 368                break;
 369        case 24:
 370                val = 0x10;
 371                break;
 372        case 16:
 373                val = 0xc;
 374                break;
 375        default:
 376                val = 0;
 377                dev_warn(&priv->i2c->dev,
 378                        "horus3a: invalid xtal frequency %dMHz\n",
 379                        config->xtal_freq_mhz);
 380                break;
 381        }
 382        val <<= 2;
 383        horus3a_write_reg(priv, 0x0e, val);
 384        horus3a_enter_power_save(priv);
 385        usleep_range(3000, 5000);
 386
 387        if (fe->ops.i2c_gate_ctrl)
 388                fe->ops.i2c_gate_ctrl(fe, 0);
 389
 390        memcpy(&fe->ops.tuner_ops, &horus3a_tuner_ops,
 391                                sizeof(struct dvb_tuner_ops));
 392        fe->tuner_priv = priv;
 393        dev_info(&priv->i2c->dev,
 394                "Sony HORUS3A attached on addr=%x at I2C adapter %p\n",
 395                priv->i2c_address, priv->i2c);
 396        return fe;
 397}
 398EXPORT_SYMBOL(horus3a_attach);
 399
 400MODULE_DESCRIPTION("Sony HORUS3A satellite tuner driver");
 401MODULE_AUTHOR("Sergey Kozlov <serjk@netup.ru>");
 402MODULE_LICENSE("GPL");
 403