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