1 // SPDX-License-Identifier: GPL-2.0-or-later
5 * Sony Horus3A DVB-S/S2 tuner driver
7 * Copyright 2012 Sony Corporation
8 * Copyright (C) 2014 NetUP Inc.
9 * Copyright (C) 2014 Sergey Kozlov <serjk@netup.ru>
10 * Copyright (C) 2014 Abylay Ospan <aospan@netup.ru>
13 #include <linux/slab.h>
14 #include <linux/module.h>
15 #include <linux/dvb/frontend.h>
16 #include <linux/types.h>
18 #include <media/dvb_frontend.h>
20 #define MAX_WRITE_REGSIZE 5
31 struct i2c_adapter
*i2c
;
32 enum horus3a_state state
;
34 int (*set_tuner
)(void *, int);
37 static void horus3a_i2c_debug(struct horus3a_priv
*priv
,
38 u8 reg
, u8 write
, const u8
*data
, u32 len
)
40 dev_dbg(&priv
->i2c
->dev
, "horus3a: I2C %s reg 0x%02x size %d\n",
41 (write
== 0 ? "read" : "write"), reg
, len
);
42 print_hex_dump_bytes("horus3a: I2C data: ",
43 DUMP_PREFIX_OFFSET
, data
, len
);
46 static int horus3a_write_regs(struct horus3a_priv
*priv
,
47 u8 reg
, const u8
*data
, u32 len
)
50 u8 buf
[MAX_WRITE_REGSIZE
+ 1];
51 struct i2c_msg msg
[1] = {
53 .addr
= priv
->i2c_address
,
60 if (len
+ 1 > sizeof(buf
)) {
61 dev_warn(&priv
->i2c
->dev
,"wr reg=%04x: len=%d is too big!\n",
66 horus3a_i2c_debug(priv
, reg
, 1, data
, len
);
68 memcpy(&buf
[1], data
, len
);
69 ret
= i2c_transfer(priv
->i2c
, msg
, 1);
70 if (ret
>= 0 && ret
!= 1)
73 dev_warn(&priv
->i2c
->dev
,
74 "%s: i2c wr failed=%d reg=%02x len=%d\n",
75 KBUILD_MODNAME
, ret
, reg
, len
);
81 static int horus3a_write_reg(struct horus3a_priv
*priv
, u8 reg
, u8 val
)
83 u8 tmp
= val
; /* see gcc.gnu.org/bugzilla/show_bug.cgi?id=81715 */
85 return horus3a_write_regs(priv
, reg
, &tmp
, 1);
88 static int horus3a_enter_power_save(struct horus3a_priv
*priv
)
92 dev_dbg(&priv
->i2c
->dev
, "%s()\n", __func__
);
93 if (priv
->state
== STATE_SLEEP
)
95 /* IQ Generator disable */
96 horus3a_write_reg(priv
, 0x2a, 0x79);
98 horus3a_write_reg(priv
, 0x29, 0x70);
99 /* VCO disable preparation */
100 horus3a_write_reg(priv
, 0x28, 0x3e);
101 /* VCO buffer disable */
102 horus3a_write_reg(priv
, 0x2a, 0x19);
103 /* VCO calibration disable */
104 horus3a_write_reg(priv
, 0x1c, 0x00);
105 /* Power save setting (xtal is not stopped) */
107 /* LNA is Disabled */
110 horus3a_write_regs(priv
, 0x11, data
, sizeof(data
));
111 priv
->state
= STATE_SLEEP
;
115 static int horus3a_leave_power_save(struct horus3a_priv
*priv
)
119 dev_dbg(&priv
->i2c
->dev
, "%s()\n", __func__
);
120 if (priv
->state
== STATE_ACTIVE
)
122 /* Leave power save */
124 /* LNA is Disabled */
127 horus3a_write_regs(priv
, 0x11, data
, sizeof(data
));
128 /* VCO buffer enable */
129 horus3a_write_reg(priv
, 0x2a, 0x79);
130 /* VCO calibration enable */
131 horus3a_write_reg(priv
, 0x1c, 0xc0);
133 horus3a_write_reg(priv
, 0x29, 0x71);
134 usleep_range(5000, 7000);
135 priv
->state
= STATE_ACTIVE
;
139 static int horus3a_init(struct dvb_frontend
*fe
)
141 struct horus3a_priv
*priv
= fe
->tuner_priv
;
143 dev_dbg(&priv
->i2c
->dev
, "%s()\n", __func__
);
147 static void horus3a_release(struct dvb_frontend
*fe
)
149 struct horus3a_priv
*priv
= fe
->tuner_priv
;
151 dev_dbg(&priv
->i2c
->dev
, "%s()\n", __func__
);
152 kfree(fe
->tuner_priv
);
153 fe
->tuner_priv
= NULL
;
156 static int horus3a_sleep(struct dvb_frontend
*fe
)
158 struct horus3a_priv
*priv
= fe
->tuner_priv
;
160 dev_dbg(&priv
->i2c
->dev
, "%s()\n", __func__
);
161 horus3a_enter_power_save(priv
);
165 static int horus3a_set_params(struct dvb_frontend
*fe
)
167 struct dtv_frontend_properties
*p
= &fe
->dtv_property_cache
;
168 struct horus3a_priv
*priv
= fe
->tuner_priv
;
169 u32 frequency
= p
->frequency
;
170 u32 symbol_rate
= p
->symbol_rate
/1000;
179 dev_dbg(&priv
->i2c
->dev
, "%s(): frequency %dkHz symbol_rate %dksps\n",
180 __func__
, frequency
, symbol_rate
);
182 priv
->set_tuner(priv
->set_tuner_data
, 0);
183 if (priv
->state
== STATE_SLEEP
)
184 horus3a_leave_power_save(priv
);
186 /* frequency should be X MHz (X : integer) */
187 frequency
= DIV_ROUND_CLOSEST(frequency
, 1000) * 1000;
188 if (frequency
<= 1155000) {
195 /* Assumed that fREF == 1MHz (1000kHz) */
196 ms
= DIV_ROUND_CLOSEST((frequency
* mixdiv
) / 2, 1000);
197 if (ms
> 0x7FFF) { /* 15 bit */
198 dev_err(&priv
->i2c
->dev
, "horus3a: invalid frequency %d\n",
202 if (frequency
< 975000) {
203 /* F_CTL=11100 G_CTL=001 */
206 } else if (frequency
< 1050000) {
207 /* F_CTL=11000 G_CTL=010 */
210 } else if (frequency
< 1150000) {
211 /* F_CTL=10100 G_CTL=010 */
214 } else if (frequency
< 1250000) {
215 /* F_CTL=10000 G_CTL=011 */
218 } else if (frequency
< 1350000) {
219 /* F_CTL=01100 G_CTL=100 */
222 } else if (frequency
< 1450000) {
223 /* F_CTL=01010 G_CTL=100 */
226 } else if (frequency
< 1600000) {
227 /* F_CTL=00111 G_CTL=101 */
230 } else if (frequency
< 1800000) {
231 /* F_CTL=00100 G_CTL=010 */
234 } else if (frequency
< 2000000) {
235 /* F_CTL=00010 G_CTL=001 */
239 /* F_CTL=00000 G_CTL=000 */
243 /* LPF cutoff frequency setting */
244 if (p
->delivery_system
== SYS_DVBS
) {
250 * fc_lpf = SR * (1 + rolloff) / 2 + SR / 2 =
251 * SR * 1.175 = SR * (47/40)
253 * fc_lpf = SR * (1 + rolloff) / 2 + 5 =
254 * SR * 0.675 + 5 = SR * (27/40) + 5
255 * NOTE: The result should be round up.
257 if (symbol_rate
<= 4300)
259 else if (symbol_rate
<= 10000)
260 fc_lpf
= (u8
)DIV_ROUND_UP(symbol_rate
* 47, 40000);
262 fc_lpf
= (u8
)DIV_ROUND_UP(symbol_rate
* 27, 40000) + 5;
263 /* 5 <= fc_lpf <= 36 */
266 } else if (p
->delivery_system
== SYS_DVBS2
) {
271 * fc_lpf = SR * (1 + rolloff) / 2 + SR / 2
273 * fc_lpf = SR * (1 + rolloff) / 2 + 5
274 * NOTE: The result should be round up.
276 if (symbol_rate
<= 4500)
278 else if (symbol_rate
<= 10000)
279 fc_lpf
= (u8
)((symbol_rate
* 11 + (10000-1)) / 10000);
281 fc_lpf
= (u8
)((symbol_rate
* 3 + (5000-1)) / 5000 + 5);
282 /* 5 <= fc_lpf <= 36 is valid */
286 dev_err(&priv
->i2c
->dev
,
287 "horus3a: invalid delivery system %d\n",
292 data
[0] = (u8
)((ms
>> 7) & 0xFF);
293 data
[1] = (u8
)((ms
<< 1) & 0xFF);
296 data
[4] = (u8
)(mdiv
<< 7);
297 horus3a_write_regs(priv
, 0x00, data
, sizeof(data
));
298 /* Write G_CTL, F_CTL */
299 horus3a_write_reg(priv
, 0x09, (u8
)((g_ctl
<< 5) | f_ctl
));
300 /* Write LPF cutoff frequency */
301 horus3a_write_reg(priv
, 0x37, (u8
)(0x80 | (fc_lpf
<< 1)));
302 /* Start Calibration */
303 horus3a_write_reg(priv
, 0x05, 0x80);
304 /* IQ Generator enable */
305 horus3a_write_reg(priv
, 0x2a, 0x7b);
306 /* tuner stabilization time */
308 /* Store tuned frequency to the struct */
309 priv
->frequency
= ms
* 2 * 1000 / mixdiv
;
313 static int horus3a_get_frequency(struct dvb_frontend
*fe
, u32
*frequency
)
315 struct horus3a_priv
*priv
= fe
->tuner_priv
;
317 *frequency
= priv
->frequency
;
321 static const struct dvb_tuner_ops horus3a_tuner_ops
= {
323 .name
= "Sony Horus3a",
324 .frequency_min_hz
= 950 * MHz
,
325 .frequency_max_hz
= 2150 * MHz
,
326 .frequency_step_hz
= 1 * MHz
,
328 .init
= horus3a_init
,
329 .release
= horus3a_release
,
330 .sleep
= horus3a_sleep
,
331 .set_params
= horus3a_set_params
,
332 .get_frequency
= horus3a_get_frequency
,
335 struct dvb_frontend
*horus3a_attach(struct dvb_frontend
*fe
,
336 const struct horus3a_config
*config
,
337 struct i2c_adapter
*i2c
)
340 struct horus3a_priv
*priv
= NULL
;
342 priv
= kzalloc(sizeof(struct horus3a_priv
), GFP_KERNEL
);
345 priv
->i2c_address
= (config
->i2c_address
>> 1);
347 priv
->set_tuner_data
= config
->set_tuner_priv
;
348 priv
->set_tuner
= config
->set_tuner_callback
;
350 if (fe
->ops
.i2c_gate_ctrl
)
351 fe
->ops
.i2c_gate_ctrl(fe
, 1);
353 /* wait 4ms after power on */
354 usleep_range(4000, 6000);
355 /* IQ Generator disable */
356 horus3a_write_reg(priv
, 0x2a, 0x79);
357 /* REF_R = Xtal Frequency */
358 buf
[0] = config
->xtal_freq_mhz
;
359 buf
[1] = config
->xtal_freq_mhz
;
362 horus3a_write_regs(priv
, 0x6, buf
, 3);
363 /* IQ Out = Single Ended */
364 horus3a_write_reg(priv
, 0x0a, 0x40);
365 switch (config
->xtal_freq_mhz
) {
377 dev_warn(&priv
->i2c
->dev
,
378 "horus3a: invalid xtal frequency %dMHz\n",
379 config
->xtal_freq_mhz
);
383 horus3a_write_reg(priv
, 0x0e, val
);
384 horus3a_enter_power_save(priv
);
385 usleep_range(3000, 5000);
387 if (fe
->ops
.i2c_gate_ctrl
)
388 fe
->ops
.i2c_gate_ctrl(fe
, 0);
390 memcpy(&fe
->ops
.tuner_ops
, &horus3a_tuner_ops
,
391 sizeof(struct dvb_tuner_ops
));
392 fe
->tuner_priv
= priv
;
393 dev_info(&priv
->i2c
->dev
,
394 "Sony HORUS3A attached on addr=%x at I2C adapter %p\n",
395 priv
->i2c_address
, priv
->i2c
);
398 EXPORT_SYMBOL(horus3a_attach
);
400 MODULE_DESCRIPTION("Sony HORUS3A satellite tuner driver");
401 MODULE_AUTHOR("Sergey Kozlov <serjk@netup.ru>");
402 MODULE_LICENSE("GPL");