Linux-libre 5.7.6-gnu
[librecmc/linux-libre.git] / drivers / media / tuners / qm1d1b0004.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Sharp QM1D1B0004 satellite tuner
4  *
5  * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com>
6  *
7  * based on (former) drivers/media/pci/pt1/va1j5jf8007s.c.
8  */
9
10 /*
11  * Note:
12  * Since the data-sheet of this tuner chip is not available,
13  * this driver lacks some tuner_ops and config options.
14  * In addition, the implementation might be dependent on the specific use
15  * in the FE module: VA1J5JF8007S and/or in the product: Earthsoft PT1/PT2.
16  */
17
18 #include <linux/kernel.h>
19 #include <linux/module.h>
20 #include <media/dvb_frontend.h>
21 #include "qm1d1b0004.h"
22
23 /*
24  * Tuner I/F (copied from the former va1j5jf8007s.c)
25  * b[0] I2C addr
26  * b[1] "0":1, BG:2, divider_quotient[7:3]:5
27  * b[2] divider_quotient[2:0]:3, divider_remainder:5
28  * b[3] "111":3, LPF[3:2]:2, TM:1, "0":1, REF:1
29  * b[4] BANDX, PSC:1, LPF[1:0]:2, DIV:1, "0":1
30  *
31  * PLL frequency step :=
32  *    REF == 0 -> PLL XTL frequency(4MHz) / 8
33  *    REF == 1 -> PLL XTL frequency(4MHz) / 4
34  *
35  * PreScaler :=
36  *    PSC == 0 -> x32
37  *    PSC == 1 -> x16
38  *
39  * divider_quotient := (frequency / PLL frequency step) / PreScaler
40  * divider_remainder := (frequency / PLL frequency step) % PreScaler
41  *
42  * LPF := LPF Frequency / 1000 / 2 - 2
43  * LPF Frequency @ baudrate=28.86Mbps = 30000
44  *
45  * band (1..9)
46  *   band 1 (freq <  986000) -> DIV:1, BANDX:5, PSC:1
47  *   band 2 (freq < 1072000) -> DIV:1, BANDX:6, PSC:1
48  *   band 3 (freq < 1154000) -> DIV:1, BANDX:7, PSC:0
49  *   band 4 (freq < 1291000) -> DIV:0, BANDX:1, PSC:0
50  *   band 5 (freq < 1447000) -> DIV:0, BANDX:2, PSC:0
51  *   band 6 (freq < 1615000) -> DIV:0, BANDX:3, PSC:0
52  *   band 7 (freq < 1791000) -> DIV:0, BANDX:4, PSC:0
53  *   band 8 (freq < 1972000) -> DIV:0, BANDX:5, PSC:0
54  *   band 9 (freq < 2150000) -> DIV:0, BANDX:6, PSC:0
55  */
56
57 #define QM1D1B0004_PSC_MASK (1 << 4)
58
59 #define QM1D1B0004_XTL_FREQ 4000
60 #define QM1D1B0004_LPF_FALLBACK 30000
61
62 #if 0 /* Currently unused */
63 static const struct qm1d1b0004_config default_cfg = {
64         .lpf_freq = QM1D1B0004_CFG_LPF_DFLT,
65         .half_step = false,
66 };
67 #endif
68
69 struct qm1d1b0004_state {
70         struct qm1d1b0004_config cfg;
71         struct i2c_client *i2c;
72 };
73
74
75 struct qm1d1b0004_cb_map {
76         u32 frequency;
77         u8 cb;
78 };
79
80 static const struct qm1d1b0004_cb_map cb_maps[] = {
81         {  986000, 0xb2 },
82         { 1072000, 0xd2 },
83         { 1154000, 0xe2 },
84         { 1291000, 0x20 },
85         { 1447000, 0x40 },
86         { 1615000, 0x60 },
87         { 1791000, 0x80 },
88         { 1972000, 0xa0 },
89 };
90
91 static u8 lookup_cb(u32 frequency)
92 {
93         int i;
94         const struct qm1d1b0004_cb_map *map;
95
96         for (i = 0; i < ARRAY_SIZE(cb_maps); i++) {
97                 map = &cb_maps[i];
98                 if (frequency < map->frequency)
99                         return map->cb;
100         }
101         return 0xc0;
102 }
103
104 static int qm1d1b0004_set_params(struct dvb_frontend *fe)
105 {
106         struct qm1d1b0004_state *state;
107         u32 frequency, pll, lpf_freq;
108         u16 word;
109         u8 buf[4], cb, lpf;
110         int ret;
111
112         state = fe->tuner_priv;
113         frequency = fe->dtv_property_cache.frequency;
114
115         pll = QM1D1B0004_XTL_FREQ / 4;
116         if (state->cfg.half_step)
117                 pll /= 2;
118         word = DIV_ROUND_CLOSEST(frequency, pll);
119         cb = lookup_cb(frequency);
120         if (cb & QM1D1B0004_PSC_MASK)
121                 word = (word << 1 & ~0x1f) | (word & 0x0f);
122
123         /* step.1: set frequency with BG:2, TM:0(4MHZ), LPF:4MHz */
124         buf[0] = 0x40 | word >> 8;
125         buf[1] = word;
126         /* inconsisnten with the above I/F doc. maybe the doc is wrong */
127         buf[2] = 0xe0 | state->cfg.half_step;
128         buf[3] = cb;
129         ret = i2c_master_send(state->i2c, buf, 4);
130         if (ret < 0)
131                 return ret;
132
133         /* step.2: set TM:1 */
134         buf[0] = 0xe4 | state->cfg.half_step;
135         ret = i2c_master_send(state->i2c, buf, 1);
136         if (ret < 0)
137                 return ret;
138         msleep(20);
139
140         /* step.3: set LPF */
141         lpf_freq = state->cfg.lpf_freq;
142         if (lpf_freq == QM1D1B0004_CFG_LPF_DFLT)
143                 lpf_freq = fe->dtv_property_cache.symbol_rate / 1000;
144         if (lpf_freq == 0)
145                 lpf_freq = QM1D1B0004_LPF_FALLBACK;
146         lpf = DIV_ROUND_UP(lpf_freq, 2000) - 2;
147         buf[0] = 0xe4 | ((lpf & 0x0c) << 1) | state->cfg.half_step;
148         buf[1] = cb | ((lpf & 0x03) << 2);
149         ret = i2c_master_send(state->i2c, buf, 2);
150         if (ret < 0)
151                 return ret;
152
153         /* step.4: read PLL lock? */
154         buf[0] = 0;
155         ret = i2c_master_recv(state->i2c, buf, 1);
156         if (ret < 0)
157                 return ret;
158         return 0;
159 }
160
161
162 static int qm1d1b0004_set_config(struct dvb_frontend *fe, void *priv_cfg)
163 {
164         struct qm1d1b0004_state *state;
165
166         state = fe->tuner_priv;
167         memcpy(&state->cfg, priv_cfg, sizeof(state->cfg));
168         return 0;
169 }
170
171
172 static int qm1d1b0004_init(struct dvb_frontend *fe)
173 {
174         struct qm1d1b0004_state *state;
175         u8 buf[2] = {0xf8, 0x04};
176
177         state = fe->tuner_priv;
178         if (state->cfg.half_step)
179                 buf[0] |= 0x01;
180
181         return i2c_master_send(state->i2c, buf, 2);
182 }
183
184
185 static const struct dvb_tuner_ops qm1d1b0004_ops = {
186         .info = {
187                 .name = "Sharp qm1d1b0004",
188
189                 .frequency_min_hz =  950 * MHz,
190                 .frequency_max_hz = 2150 * MHz,
191         },
192
193         .init = qm1d1b0004_init,
194
195         .set_params = qm1d1b0004_set_params,
196         .set_config = qm1d1b0004_set_config,
197 };
198
199 static int
200 qm1d1b0004_probe(struct i2c_client *client, const struct i2c_device_id *id)
201 {
202         struct dvb_frontend *fe;
203         struct qm1d1b0004_config *cfg;
204         struct qm1d1b0004_state *state;
205         int ret;
206
207         cfg = client->dev.platform_data;
208         fe = cfg->fe;
209         i2c_set_clientdata(client, fe);
210
211         fe->tuner_priv = kzalloc(sizeof(struct qm1d1b0004_state), GFP_KERNEL);
212         if (!fe->tuner_priv) {
213                 ret = -ENOMEM;
214                 goto err_mem;
215         }
216
217         memcpy(&fe->ops.tuner_ops, &qm1d1b0004_ops, sizeof(fe->ops.tuner_ops));
218
219         state = fe->tuner_priv;
220         state->i2c = client;
221         ret = qm1d1b0004_set_config(fe, cfg);
222         if (ret != 0)
223                 goto err_priv;
224
225         dev_info(&client->dev, "Sharp QM1D1B0004 attached.\n");
226         return 0;
227
228 err_priv:
229         kfree(fe->tuner_priv);
230 err_mem:
231         fe->tuner_priv = NULL;
232         return ret;
233 }
234
235 static int qm1d1b0004_remove(struct i2c_client *client)
236 {
237         struct dvb_frontend *fe;
238
239         fe = i2c_get_clientdata(client);
240         kfree(fe->tuner_priv);
241         fe->tuner_priv = NULL;
242         return 0;
243 }
244
245
246 static const struct i2c_device_id qm1d1b0004_id[] = {
247         {"qm1d1b0004", 0},
248         {}
249 };
250
251 MODULE_DEVICE_TABLE(i2c, qm1d1b0004_id);
252
253 static struct i2c_driver qm1d1b0004_driver = {
254         .driver = {
255                 .name = "qm1d1b0004",
256         },
257         .probe    = qm1d1b0004_probe,
258         .remove   = qm1d1b0004_remove,
259         .id_table = qm1d1b0004_id,
260 };
261
262 module_i2c_driver(qm1d1b0004_driver);
263
264 MODULE_DESCRIPTION("Sharp QM1D1B0004");
265 MODULE_AUTHOR("Akihiro Tsukada");
266 MODULE_LICENSE("GPL");