Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / drivers / media / platform / sti / c8sectpfe / c8sectpfe-dvb.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  *  c8sectpfe-dvb.c - C8SECTPFE STi DVB driver
4  *
5  * Copyright (c) STMicroelectronics 2015
6  *
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 #include <linux/version.h>
15
16 #include <dt-bindings/media/c8sectpfe.h>
17
18 #include "c8sectpfe-common.h"
19 #include "c8sectpfe-core.h"
20 #include "c8sectpfe-dvb.h"
21
22 #include "dvb-pll.h"
23 #include "lnbh24.h"
24 #include "stv0367.h"
25 #include "stv0367_priv.h"
26 #include "stv6110x.h"
27 #include "stv090x.h"
28 #include "tda18212.h"
29
30 static inline const char *dvb_card_str(unsigned int c)
31 {
32         switch (c) {
33         case STV0367_TDA18212_NIMA_1:   return "STV0367_TDA18212_NIMA_1";
34         case STV0367_TDA18212_NIMA_2:   return "STV0367_TDA18212_NIMA_2";
35         case STV0367_TDA18212_NIMB_1:   return "STV0367_TDA18212_NIMB_1";
36         case STV0367_TDA18212_NIMB_2:   return "STV0367_TDA18212_NIMB_2";
37         case STV0903_6110_LNB24_NIMA:   return "STV0903_6110_LNB24_NIMA";
38         case STV0903_6110_LNB24_NIMB:   return "STV0903_6110_LNB24_NIMB";
39         default:                        return "unknown dvb frontend card";
40         }
41 }
42
43 static struct stv090x_config stv090x_config = {
44         .device                 = STV0903,
45         .demod_mode             = STV090x_SINGLE,
46         .clk_mode               = STV090x_CLK_EXT,
47         .xtal                   = 16000000,
48         .address                = 0x69,
49
50         .ts1_mode               = STV090x_TSMODE_SERIAL_CONTINUOUS,
51         .ts2_mode               = STV090x_TSMODE_SERIAL_CONTINUOUS,
52
53         .repeater_level         = STV090x_RPTLEVEL_64,
54
55         .tuner_init             = NULL,
56         .tuner_set_mode         = NULL,
57         .tuner_set_frequency    = NULL,
58         .tuner_get_frequency    = NULL,
59         .tuner_set_bandwidth    = NULL,
60         .tuner_get_bandwidth    = NULL,
61         .tuner_set_bbgain       = NULL,
62         .tuner_get_bbgain       = NULL,
63         .tuner_set_refclk       = NULL,
64         .tuner_get_status       = NULL,
65 };
66
67 static struct stv6110x_config stv6110x_config = {
68         .addr                   = 0x60,
69         .refclk                 = 16000000,
70 };
71
72 #define NIMA 0
73 #define NIMB 1
74
75 static struct stv0367_config stv0367_tda18212_config[] = {
76         {
77                 .demod_address = 0x1c,
78                 .xtal = 16000000,
79                 .if_khz = 4500,
80                 .if_iq_mode = FE_TER_NORMAL_IF_TUNER,
81                 .ts_mode = STV0367_SERIAL_PUNCT_CLOCK,
82                 .clk_pol = STV0367_CLOCKPOLARITY_DEFAULT,
83         }, {
84                 .demod_address = 0x1d,
85                 .xtal = 16000000,
86                 .if_khz = 4500,
87                 .if_iq_mode = FE_TER_NORMAL_IF_TUNER,
88                 .ts_mode = STV0367_SERIAL_PUNCT_CLOCK,
89                 .clk_pol = STV0367_CLOCKPOLARITY_DEFAULT,
90         }, {
91                 .demod_address = 0x1e,
92                 .xtal = 16000000,
93                 .if_khz = 4500,
94                 .if_iq_mode = FE_TER_NORMAL_IF_TUNER,
95                 .ts_mode = STV0367_SERIAL_PUNCT_CLOCK,
96                 .clk_pol = STV0367_CLOCKPOLARITY_DEFAULT,
97         },
98 };
99
100 static struct tda18212_config tda18212_conf = {
101         .if_dvbt_6 = 4150,
102         .if_dvbt_7 = 4150,
103         .if_dvbt_8 = 4500,
104         .if_dvbc = 5000,
105 };
106
107 int c8sectpfe_frontend_attach(struct dvb_frontend **fe,
108                 struct c8sectpfe *c8sectpfe,
109                 struct channel_info *tsin, int chan_num)
110 {
111         struct tda18212_config *tda18212;
112         const struct stv6110x_devctl *fe2;
113         struct i2c_client *client;
114         struct i2c_board_info tda18212_info = {
115                 .type = "tda18212",
116                 .addr = 0x60,
117         };
118
119         if (!tsin)
120                 return -EINVAL;
121
122         switch (tsin->dvb_card) {
123
124         case STV0367_TDA18212_NIMA_1:
125         case STV0367_TDA18212_NIMA_2:
126         case STV0367_TDA18212_NIMB_1:
127         case STV0367_TDA18212_NIMB_2:
128                 if (tsin->dvb_card == STV0367_TDA18212_NIMA_1)
129                         *fe = dvb_attach(stv0367ter_attach,
130                                  &stv0367_tda18212_config[0],
131                                         tsin->i2c_adapter);
132                 else if (tsin->dvb_card == STV0367_TDA18212_NIMB_1)
133                         *fe = dvb_attach(stv0367ter_attach,
134                                  &stv0367_tda18212_config[1],
135                                         tsin->i2c_adapter);
136                 else
137                         *fe = dvb_attach(stv0367ter_attach,
138                                  &stv0367_tda18212_config[2],
139                                         tsin->i2c_adapter);
140
141                 if (!*fe) {
142                         dev_err(c8sectpfe->device,
143                                 "%s: stv0367ter_attach failed for NIM card %s\n"
144                                 , __func__, dvb_card_str(tsin->dvb_card));
145                         return -ENODEV;
146                 }
147
148                 /*
149                  * init the demod so that i2c gate_ctrl
150                  * to the tuner works correctly
151                  */
152                 (*fe)->ops.init(*fe);
153
154                 /* Allocate the tda18212 structure */
155                 tda18212 = devm_kzalloc(c8sectpfe->device,
156                                         sizeof(struct tda18212_config),
157                                         GFP_KERNEL);
158                 if (!tda18212) {
159                         dev_err(c8sectpfe->device,
160                                 "%s: devm_kzalloc failed\n", __func__);
161                         return -ENOMEM;
162                 }
163
164                 memcpy(tda18212, &tda18212_conf,
165                         sizeof(struct tda18212_config));
166
167                 tda18212->fe = (*fe);
168
169                 tda18212_info.platform_data = tda18212;
170
171                 /* attach tuner */
172                 request_module("tda18212");
173                 client = i2c_new_device(tsin->i2c_adapter, &tda18212_info);
174                 if (!client || !client->dev.driver) {
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 }