1 // SPDX-License-Identifier: GPL-2.0
3 * Sharp QM1D1B0004 satellite tuner
5 * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com>
7 * based on (former) drivers/media/pci/pt1/va1j5jf8007s.c.
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.
18 #include <linux/kernel.h>
19 #include <linux/module.h>
20 #include <media/dvb_frontend.h>
21 #include "qm1d1b0004.h"
24 * Tuner I/F (copied from the former va1j5jf8007s.c)
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
31 * PLL frequency step :=
32 * REF == 0 -> PLL XTL frequency(4MHz) / 8
33 * REF == 1 -> PLL XTL frequency(4MHz) / 4
39 * divider_quotient := (frequency / PLL frequency step) / PreScaler
40 * divider_remainder := (frequency / PLL frequency step) % PreScaler
42 * LPF := LPF Frequency / 1000 / 2 - 2
43 * LPF Frequency @ baudrate=28.86Mbps = 30000
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
57 #define QM1D1B0004_PSC_MASK (1 << 4)
59 #define QM1D1B0004_XTL_FREQ 4000
60 #define QM1D1B0004_LPF_FALLBACK 30000
62 #if 0 /* Currently unused */
63 static const struct qm1d1b0004_config default_cfg
= {
64 .lpf_freq
= QM1D1B0004_CFG_LPF_DFLT
,
69 struct qm1d1b0004_state
{
70 struct qm1d1b0004_config cfg
;
71 struct i2c_client
*i2c
;
75 struct qm1d1b0004_cb_map
{
80 static const struct qm1d1b0004_cb_map cb_maps
[] = {
91 static u8
lookup_cb(u32 frequency
)
94 const struct qm1d1b0004_cb_map
*map
;
96 for (i
= 0; i
< ARRAY_SIZE(cb_maps
); i
++) {
98 if (frequency
< map
->frequency
)
104 static int qm1d1b0004_set_params(struct dvb_frontend
*fe
)
106 struct qm1d1b0004_state
*state
;
107 u32 frequency
, pll
, lpf_freq
;
112 state
= fe
->tuner_priv
;
113 frequency
= fe
->dtv_property_cache
.frequency
;
115 pll
= QM1D1B0004_XTL_FREQ
/ 4;
116 if (state
->cfg
.half_step
)
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);
123 /* step.1: set frequency with BG:2, TM:0(4MHZ), LPF:4MHz */
124 buf
[0] = 0x40 | word
>> 8;
126 /* inconsisnten with the above I/F doc. maybe the doc is wrong */
127 buf
[2] = 0xe0 | state
->cfg
.half_step
;
129 ret
= i2c_master_send(state
->i2c
, buf
, 4);
133 /* step.2: set TM:1 */
134 buf
[0] = 0xe4 | state
->cfg
.half_step
;
135 ret
= i2c_master_send(state
->i2c
, buf
, 1);
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;
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);
153 /* step.4: read PLL lock? */
155 ret
= i2c_master_recv(state
->i2c
, buf
, 1);
162 static int qm1d1b0004_set_config(struct dvb_frontend
*fe
, void *priv_cfg
)
164 struct qm1d1b0004_state
*state
;
166 state
= fe
->tuner_priv
;
167 memcpy(&state
->cfg
, priv_cfg
, sizeof(state
->cfg
));
172 static int qm1d1b0004_init(struct dvb_frontend
*fe
)
174 struct qm1d1b0004_state
*state
;
175 u8 buf
[2] = {0xf8, 0x04};
177 state
= fe
->tuner_priv
;
178 if (state
->cfg
.half_step
)
181 return i2c_master_send(state
->i2c
, buf
, 2);
185 static const struct dvb_tuner_ops qm1d1b0004_ops
= {
187 .name
= "Sharp qm1d1b0004",
189 .frequency_min_hz
= 950 * MHz
,
190 .frequency_max_hz
= 2150 * MHz
,
193 .init
= qm1d1b0004_init
,
195 .set_params
= qm1d1b0004_set_params
,
196 .set_config
= qm1d1b0004_set_config
,
200 qm1d1b0004_probe(struct i2c_client
*client
, const struct i2c_device_id
*id
)
202 struct dvb_frontend
*fe
;
203 struct qm1d1b0004_config
*cfg
;
204 struct qm1d1b0004_state
*state
;
207 cfg
= client
->dev
.platform_data
;
209 i2c_set_clientdata(client
, fe
);
211 fe
->tuner_priv
= kzalloc(sizeof(struct qm1d1b0004_state
), GFP_KERNEL
);
212 if (!fe
->tuner_priv
) {
217 memcpy(&fe
->ops
.tuner_ops
, &qm1d1b0004_ops
, sizeof(fe
->ops
.tuner_ops
));
219 state
= fe
->tuner_priv
;
221 ret
= qm1d1b0004_set_config(fe
, cfg
);
225 dev_info(&client
->dev
, "Sharp QM1D1B0004 attached.\n");
229 kfree(fe
->tuner_priv
);
231 fe
->tuner_priv
= NULL
;
235 static int qm1d1b0004_remove(struct i2c_client
*client
)
237 struct dvb_frontend
*fe
;
239 fe
= i2c_get_clientdata(client
);
240 kfree(fe
->tuner_priv
);
241 fe
->tuner_priv
= NULL
;
246 static const struct i2c_device_id qm1d1b0004_id
[] = {
251 MODULE_DEVICE_TABLE(i2c
, qm1d1b0004_id
);
253 static struct i2c_driver qm1d1b0004_driver
= {
255 .name
= "qm1d1b0004",
257 .probe
= qm1d1b0004_probe
,
258 .remove
= qm1d1b0004_remove
,
259 .id_table
= qm1d1b0004_id
,
262 module_i2c_driver(qm1d1b0004_driver
);
264 MODULE_DESCRIPTION("Sharp QM1D1B0004");
265 MODULE_AUTHOR("Akihiro Tsukada");
266 MODULE_LICENSE("GPL");