linux/drivers/media/platform/sti/c8sectpfe/c8sectpfe-dvb.c
<<
>>
Prefs
   1/*
   2 *  c8sectpfe-dvb.c - C8SECTPFE STi DVB driver
   3 *
   4 * Copyright (c) STMicroelectronics 2015
   5 *
   6 *  Author Peter Griffin <peter.griffin@linaro.org>
   7 *
   8 *  This program is free software; you can redistribute it and/or modify
   9 *  it under the terms of the GNU General Public License as published by
  10 *  the Free Software Foundation; either version 2 of the License, or
  11 *  (at your option) any later version.
  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 *
  17 *  GNU General Public License for more details.
  18 */
  19#include <linux/completion.h>
  20#include <linux/delay.h>
  21#include <linux/i2c.h>
  22#include <linux/interrupt.h>
  23#include <linux/version.h>
  24
  25#include <dt-bindings/media/c8sectpfe.h>
  26
  27#include "c8sectpfe-common.h"
  28#include "c8sectpfe-core.h"
  29#include "c8sectpfe-dvb.h"
  30
  31#include "dvb-pll.h"
  32#include "lnbh24.h"
  33#include "stv0367.h"
  34#include "stv0367_priv.h"
  35#include "stv6110x.h"
  36#include "stv090x.h"
  37#include "tda18212.h"
  38
  39static inline const char *dvb_card_str(unsigned int c)
  40{
  41        switch (c) {
  42        case STV0367_TDA18212_NIMA_1:   return "STV0367_TDA18212_NIMA_1";
  43        case STV0367_TDA18212_NIMA_2:   return "STV0367_TDA18212_NIMA_2";
  44        case STV0367_TDA18212_NIMB_1:   return "STV0367_TDA18212_NIMB_1";
  45        case STV0367_TDA18212_NIMB_2:   return "STV0367_TDA18212_NIMB_2";
  46        case STV0903_6110_LNB24_NIMA:   return "STV0903_6110_LNB24_NIMA";
  47        case STV0903_6110_LNB24_NIMB:   return "STV0903_6110_LNB24_NIMB";
  48        default:                        return "unknown dvb frontend card";
  49        }
  50}
  51
  52static struct stv090x_config stv090x_config = {
  53        .device                 = STV0903,
  54        .demod_mode             = STV090x_SINGLE,
  55        .clk_mode               = STV090x_CLK_EXT,
  56        .xtal                   = 16000000,
  57        .address                = 0x69,
  58
  59        .ts1_mode               = STV090x_TSMODE_SERIAL_CONTINUOUS,
  60        .ts2_mode               = STV090x_TSMODE_SERIAL_CONTINUOUS,
  61
  62        .repeater_level         = STV090x_RPTLEVEL_64,
  63
  64        .tuner_init             = NULL,
  65        .tuner_set_mode         = NULL,
  66        .tuner_set_frequency    = NULL,
  67        .tuner_get_frequency    = NULL,
  68        .tuner_set_bandwidth    = NULL,
  69        .tuner_get_bandwidth    = NULL,
  70        .tuner_set_bbgain       = NULL,
  71        .tuner_get_bbgain       = NULL,
  72        .tuner_set_refclk       = NULL,
  73        .tuner_get_status       = NULL,
  74};
  75
  76static struct stv6110x_config stv6110x_config = {
  77        .addr                   = 0x60,
  78        .refclk                 = 16000000,
  79};
  80
  81#define NIMA 0
  82#define NIMB 1
  83
  84static struct stv0367_config stv0367_tda18212_config[] = {
  85        {
  86                .demod_address = 0x1c,
  87                .xtal = 16000000,
  88                .if_khz = 4500,
  89                .if_iq_mode = FE_TER_NORMAL_IF_TUNER,
  90                .ts_mode = STV0367_SERIAL_PUNCT_CLOCK,
  91                .clk_pol = STV0367_CLOCKPOLARITY_DEFAULT,
  92        }, {
  93                .demod_address = 0x1d,
  94                .xtal = 16000000,
  95                .if_khz = 4500,
  96                .if_iq_mode = FE_TER_NORMAL_IF_TUNER,
  97                .ts_mode = STV0367_SERIAL_PUNCT_CLOCK,
  98                .clk_pol = STV0367_CLOCKPOLARITY_DEFAULT,
  99        }, {
 100                .demod_address = 0x1e,
 101                .xtal = 16000000,
 102                .if_khz = 4500,
 103                .if_iq_mode = FE_TER_NORMAL_IF_TUNER,
 104                .ts_mode = STV0367_SERIAL_PUNCT_CLOCK,
 105                .clk_pol = STV0367_CLOCKPOLARITY_DEFAULT,
 106        },
 107};
 108
 109static struct tda18212_config tda18212_conf = {
 110        .if_dvbt_6 = 4150,
 111        .if_dvbt_7 = 4150,
 112        .if_dvbt_8 = 4500,
 113        .if_dvbc = 5000,
 114};
 115
 116int c8sectpfe_frontend_attach(struct dvb_frontend **fe,
 117                struct c8sectpfe *c8sectpfe,
 118                struct channel_info *tsin, int chan_num)
 119{
 120        struct tda18212_config *tda18212;
 121        const struct stv6110x_devctl *fe2;
 122        struct i2c_client *client;
 123        struct i2c_board_info tda18212_info = {
 124                .type = "tda18212",
 125                .addr = 0x60,
 126        };
 127
 128        if (!tsin)
 129                return -EINVAL;
 130
 131        switch (tsin->dvb_card) {
 132
 133        case STV0367_TDA18212_NIMA_1:
 134        case STV0367_TDA18212_NIMA_2:
 135        case STV0367_TDA18212_NIMB_1:
 136        case STV0367_TDA18212_NIMB_2:
 137                if (tsin->dvb_card == STV0367_TDA18212_NIMA_1)
 138                        *fe = dvb_attach(stv0367ter_attach,
 139                                 &stv0367_tda18212_config[0],
 140                                        tsin->i2c_adapter);
 141                else if (tsin->dvb_card == STV0367_TDA18212_NIMB_1)
 142                        *fe = dvb_attach(stv0367ter_attach,
 143                                 &stv0367_tda18212_config[1],
 144                                        tsin->i2c_adapter);
 145                else
 146                        *fe = dvb_attach(stv0367ter_attach,
 147                                 &stv0367_tda18212_config[2],
 148                                        tsin->i2c_adapter);
 149
 150                if (!*fe) {
 151                        dev_err(c8sectpfe->device,
 152                                "%s: stv0367ter_attach failed for NIM card %s\n"
 153                                , __func__, dvb_card_str(tsin->dvb_card));
 154                        return -ENODEV;
 155                };
 156
 157                /*
 158                 * init the demod so that i2c gate_ctrl
 159                 * to the tuner works correctly
 160                 */
 161                (*fe)->ops.init(*fe);
 162
 163                /* Allocate the tda18212 structure */
 164                tda18212 = devm_kzalloc(c8sectpfe->device,
 165                                        sizeof(struct tda18212_config),
 166                                        GFP_KERNEL);
 167                if (!tda18212) {
 168                        dev_err(c8sectpfe->device,
 169                                "%s: devm_kzalloc failed\n", __func__);
 170                        return -ENOMEM;
 171                }
 172
 173                memcpy(tda18212, &tda18212_conf,
 174                        sizeof(struct tda18212_config));
 175
 176                tda18212->fe = (*fe);
 177
 178                tda18212_info.platform_data = tda18212;
 179
 180                /* attach tuner */
 181                request_module("tda18212");
 182                client = i2c_new_device(tsin->i2c_adapter, &tda18212_info);
 183                if (!client || !client->dev.driver) {
 184                        dvb_frontend_detach(*fe);
 185                        return -ENODEV;
 186                }
 187
 188                if (!try_module_get(client->dev.driver->owner)) {
 189                        i2c_unregister_device(client);
 190                        dvb_frontend_detach(*fe);
 191                        return -ENODEV;
 192                }
 193
 194                tsin->i2c_client = client;
 195
 196                break;
 197
 198        case STV0903_6110_LNB24_NIMA:
 199                *fe = dvb_attach(stv090x_attach,        &stv090x_config,
 200                                tsin->i2c_adapter, STV090x_DEMODULATOR_0);
 201                if (!*fe) {
 202                        dev_err(c8sectpfe->device, "%s: stv090x_attach failed\n"
 203                                "\tfor NIM card %s\n",
 204                                __func__, dvb_card_str(tsin->dvb_card));
 205                        return -ENODEV;
 206                }
 207
 208                fe2 = dvb_attach(stv6110x_attach, *fe,
 209                                        &stv6110x_config, tsin->i2c_adapter);
 210                if (!fe2) {
 211                        dev_err(c8sectpfe->device,
 212                                "%s: stv6110x_attach failed for NIM card %s\n"
 213                                , __func__, dvb_card_str(tsin->dvb_card));
 214                        return -ENODEV;
 215                };
 216
 217                stv090x_config.tuner_init = fe2->tuner_init;
 218                stv090x_config.tuner_set_mode = fe2->tuner_set_mode;
 219                stv090x_config.tuner_set_frequency = fe2->tuner_set_frequency;
 220                stv090x_config.tuner_get_frequency = fe2->tuner_get_frequency;
 221                stv090x_config.tuner_set_bandwidth = fe2->tuner_set_bandwidth;
 222                stv090x_config.tuner_get_bandwidth = fe2->tuner_get_bandwidth;
 223                stv090x_config.tuner_set_bbgain = fe2->tuner_set_bbgain;
 224                stv090x_config.tuner_get_bbgain = fe2->tuner_get_bbgain;
 225                stv090x_config.tuner_set_refclk = fe2->tuner_set_refclk;
 226                stv090x_config.tuner_get_status = fe2->tuner_get_status;
 227
 228                dvb_attach(lnbh24_attach, *fe, tsin->i2c_adapter, 0, 0, 0x9);
 229                break;
 230
 231        default:
 232                dev_err(c8sectpfe->device,
 233                        "%s: DVB frontend card %s not yet supported\n",
 234                        __func__, dvb_card_str(tsin->dvb_card));
 235                return -ENODEV;
 236        }
 237
 238        (*fe)->id = chan_num;
 239
 240        dev_info(c8sectpfe->device,
 241                        "DVB frontend card %s successfully attached",
 242                        dvb_card_str(tsin->dvb_card));
 243        return 0;
 244}
 245