1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | Driver for ST STB6000 DVBS Silicon tuner |
4 | |
5 | Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by) |
6 | |
7 | |
8 | */ |
9 | |
10 | #include <linux/slab.h> |
11 | #include <linux/module.h> |
12 | #include <linux/dvb/frontend.h> |
13 | #include <asm/types.h> |
14 | |
15 | #include "stb6000.h" |
16 | |
17 | static int debug; |
18 | #define dprintk(args...) \ |
19 | do { \ |
20 | if (debug) \ |
21 | printk(KERN_DEBUG "stb6000: " args); \ |
22 | } while (0) |
23 | |
24 | struct stb6000_priv { |
25 | /* i2c details */ |
26 | int i2c_address; |
27 | struct i2c_adapter *i2c; |
28 | u32 frequency; |
29 | }; |
30 | |
31 | static void stb6000_release(struct dvb_frontend *fe) |
32 | { |
33 | kfree(objp: fe->tuner_priv); |
34 | fe->tuner_priv = NULL; |
35 | } |
36 | |
37 | static int stb6000_sleep(struct dvb_frontend *fe) |
38 | { |
39 | struct stb6000_priv *priv = fe->tuner_priv; |
40 | int ret; |
41 | u8 buf[] = { 10, 0 }; |
42 | struct i2c_msg msg = { |
43 | .addr = priv->i2c_address, |
44 | .flags = 0, |
45 | .buf = buf, |
46 | .len = 2 |
47 | }; |
48 | |
49 | dprintk("%s:\n" , __func__); |
50 | |
51 | if (fe->ops.i2c_gate_ctrl) |
52 | fe->ops.i2c_gate_ctrl(fe, 1); |
53 | |
54 | ret = i2c_transfer(adap: priv->i2c, msgs: &msg, num: 1); |
55 | if (ret != 1) |
56 | dprintk("%s: i2c error\n" , __func__); |
57 | |
58 | if (fe->ops.i2c_gate_ctrl) |
59 | fe->ops.i2c_gate_ctrl(fe, 0); |
60 | |
61 | return (ret == 1) ? 0 : ret; |
62 | } |
63 | |
64 | static int stb6000_set_params(struct dvb_frontend *fe) |
65 | { |
66 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; |
67 | struct stb6000_priv *priv = fe->tuner_priv; |
68 | unsigned int n, m; |
69 | int ret; |
70 | u32 freq_mhz; |
71 | int bandwidth; |
72 | u8 buf[12]; |
73 | struct i2c_msg msg = { |
74 | .addr = priv->i2c_address, |
75 | .flags = 0, |
76 | .buf = buf, |
77 | .len = 12 |
78 | }; |
79 | |
80 | dprintk("%s:\n" , __func__); |
81 | |
82 | freq_mhz = p->frequency / 1000; |
83 | bandwidth = p->symbol_rate / 1000000; |
84 | |
85 | if (bandwidth > 31) |
86 | bandwidth = 31; |
87 | |
88 | if ((freq_mhz > 949) && (freq_mhz < 2151)) { |
89 | buf[0] = 0x01; |
90 | buf[1] = 0xac; |
91 | if (freq_mhz < 1950) |
92 | buf[1] = 0xaa; |
93 | if (freq_mhz < 1800) |
94 | buf[1] = 0xa8; |
95 | if (freq_mhz < 1650) |
96 | buf[1] = 0xa6; |
97 | if (freq_mhz < 1530) |
98 | buf[1] = 0xa5; |
99 | if (freq_mhz < 1470) |
100 | buf[1] = 0xa4; |
101 | if (freq_mhz < 1370) |
102 | buf[1] = 0xa2; |
103 | if (freq_mhz < 1300) |
104 | buf[1] = 0xa1; |
105 | if (freq_mhz < 1200) |
106 | buf[1] = 0xa0; |
107 | if (freq_mhz < 1075) |
108 | buf[1] = 0xbc; |
109 | if (freq_mhz < 1000) |
110 | buf[1] = 0xba; |
111 | if (freq_mhz < 1075) { |
112 | n = freq_mhz / 8; /* vco=lo*4 */ |
113 | m = 2; |
114 | } else { |
115 | n = freq_mhz / 16; /* vco=lo*2 */ |
116 | m = 1; |
117 | } |
118 | buf[2] = n >> 1; |
119 | buf[3] = (unsigned char)(((n & 1) << 7) | |
120 | (m * freq_mhz - n * 16) | 0x60); |
121 | buf[4] = 0x04; |
122 | buf[5] = 0x0e; |
123 | |
124 | buf[6] = (unsigned char)(bandwidth); |
125 | |
126 | buf[7] = 0xd8; |
127 | buf[8] = 0xd0; |
128 | buf[9] = 0x50; |
129 | buf[10] = 0xeb; |
130 | buf[11] = 0x4f; |
131 | |
132 | if (fe->ops.i2c_gate_ctrl) |
133 | fe->ops.i2c_gate_ctrl(fe, 1); |
134 | |
135 | ret = i2c_transfer(adap: priv->i2c, msgs: &msg, num: 1); |
136 | if (ret != 1) |
137 | dprintk("%s: i2c error\n" , __func__); |
138 | |
139 | udelay(10); |
140 | if (fe->ops.i2c_gate_ctrl) |
141 | fe->ops.i2c_gate_ctrl(fe, 0); |
142 | |
143 | buf[0] = 0x07; |
144 | buf[1] = 0xdf; |
145 | buf[2] = 0xd0; |
146 | buf[3] = 0x50; |
147 | buf[4] = 0xfb; |
148 | msg.len = 5; |
149 | |
150 | if (fe->ops.i2c_gate_ctrl) |
151 | fe->ops.i2c_gate_ctrl(fe, 1); |
152 | |
153 | ret = i2c_transfer(adap: priv->i2c, msgs: &msg, num: 1); |
154 | if (ret != 1) |
155 | dprintk("%s: i2c error\n" , __func__); |
156 | |
157 | udelay(10); |
158 | if (fe->ops.i2c_gate_ctrl) |
159 | fe->ops.i2c_gate_ctrl(fe, 0); |
160 | |
161 | priv->frequency = freq_mhz * 1000; |
162 | |
163 | return (ret == 1) ? 0 : ret; |
164 | } |
165 | return -1; |
166 | } |
167 | |
168 | static int stb6000_get_frequency(struct dvb_frontend *fe, u32 *frequency) |
169 | { |
170 | struct stb6000_priv *priv = fe->tuner_priv; |
171 | *frequency = priv->frequency; |
172 | return 0; |
173 | } |
174 | |
175 | static const struct dvb_tuner_ops stb6000_tuner_ops = { |
176 | .info = { |
177 | .name = "ST STB6000" , |
178 | .frequency_min_hz = 950 * MHz, |
179 | .frequency_max_hz = 2150 * MHz |
180 | }, |
181 | .release = stb6000_release, |
182 | .sleep = stb6000_sleep, |
183 | .set_params = stb6000_set_params, |
184 | .get_frequency = stb6000_get_frequency, |
185 | }; |
186 | |
187 | struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, int addr, |
188 | struct i2c_adapter *i2c) |
189 | { |
190 | struct stb6000_priv *priv = NULL; |
191 | u8 b0[] = { 0 }; |
192 | u8 b1[] = { 0, 0 }; |
193 | struct i2c_msg msg[2] = { |
194 | { |
195 | .addr = addr, |
196 | .flags = 0, |
197 | .buf = b0, |
198 | .len = 0 |
199 | }, { |
200 | .addr = addr, |
201 | .flags = I2C_M_RD, |
202 | .buf = b1, |
203 | .len = 2 |
204 | } |
205 | }; |
206 | int ret; |
207 | |
208 | dprintk("%s:\n" , __func__); |
209 | |
210 | if (fe->ops.i2c_gate_ctrl) |
211 | fe->ops.i2c_gate_ctrl(fe, 1); |
212 | |
213 | /* is some i2c device here ? */ |
214 | ret = i2c_transfer(adap: i2c, msgs: msg, num: 2); |
215 | if (fe->ops.i2c_gate_ctrl) |
216 | fe->ops.i2c_gate_ctrl(fe, 0); |
217 | |
218 | if (ret != 2) |
219 | return NULL; |
220 | |
221 | priv = kzalloc(size: sizeof(struct stb6000_priv), GFP_KERNEL); |
222 | if (priv == NULL) |
223 | return NULL; |
224 | |
225 | priv->i2c_address = addr; |
226 | priv->i2c = i2c; |
227 | |
228 | memcpy(&fe->ops.tuner_ops, &stb6000_tuner_ops, |
229 | sizeof(struct dvb_tuner_ops)); |
230 | |
231 | fe->tuner_priv = priv; |
232 | |
233 | return fe; |
234 | } |
235 | EXPORT_SYMBOL_GPL(stb6000_attach); |
236 | |
237 | module_param(debug, int, 0644); |
238 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)." ); |
239 | |
240 | MODULE_DESCRIPTION("DVB STB6000 driver" ); |
241 | MODULE_AUTHOR("Igor M. Liplianin <liplianin@me.by>" ); |
242 | MODULE_LICENSE("GPL" ); |
243 | |