xref: /linux/drivers/media/tuners/qm1d1b0004.c (revision 95298d63c67673c654c08952672d016212b26054)
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");
267