diff options
author | Igor M. Liplianin <liplianin@me.by> | 2009-06-20 08:51:48 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-09-12 11:18:55 -0400 |
commit | 2ccf5a9906564cd06facc846c32d065752268dcf (patch) | |
tree | 114c80110f6986320d3f37c7b50ffbd044999c0e /drivers/media/dvb/frontends | |
parent | 3040b043423c1726a14595d500f6409070b1e722 (diff) |
V4L/DVB (12461): Add ce5039(zl10039) tuner support.
The code from Jan D. Louw with some minor changes.
http://article.gmane.org/gmane.linux.drivers.dvb/38163
Tested with TeVii S630 DVB-S USB card by me (Igor)
Signed-off-by: Igor M. Liplianin <liplianin@me.by>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/dvb/frontends')
-rw-r--r-- | drivers/media/dvb/frontends/Kconfig | 7 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/Makefile | 1 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/zl10039.c | 308 | ||||
-rw-r--r-- | drivers/media/dvb/frontends/zl10039.h | 40 |
4 files changed, 356 insertions, 0 deletions
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index be967ac09a3..b794e860b4e 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig | |||
@@ -81,6 +81,13 @@ config DVB_ZL10036 | |||
81 | help | 81 | help |
82 | A DVB-S tuner module. Say Y when you want to support this frontend. | 82 | A DVB-S tuner module. Say Y when you want to support this frontend. |
83 | 83 | ||
84 | config DVB_ZL10039 | ||
85 | tristate "Zarlink ZL10039 silicon tuner" | ||
86 | depends on DVB_CORE && I2C | ||
87 | default m if DVB_FE_CUSTOMISE | ||
88 | help | ||
89 | A DVB-S tuner module. Say Y when you want to support this frontend. | ||
90 | |||
84 | config DVB_S5H1420 | 91 | config DVB_S5H1420 |
85 | tristate "Samsung S5H1420 based" | 92 | tristate "Samsung S5H1420 based" |
86 | depends on DVB_CORE && I2C | 93 | depends on DVB_CORE && I2C |
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 832473c1e51..3b49d37ab5f 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile | |||
@@ -31,6 +31,7 @@ obj-$(CONFIG_DVB_SP887X) += sp887x.o | |||
31 | obj-$(CONFIG_DVB_NXT6000) += nxt6000.o | 31 | obj-$(CONFIG_DVB_NXT6000) += nxt6000.o |
32 | obj-$(CONFIG_DVB_MT352) += mt352.o | 32 | obj-$(CONFIG_DVB_MT352) += mt352.o |
33 | obj-$(CONFIG_DVB_ZL10036) += zl10036.o | 33 | obj-$(CONFIG_DVB_ZL10036) += zl10036.o |
34 | obj-$(CONFIG_DVB_ZL10039) += zl10039.o | ||
34 | obj-$(CONFIG_DVB_ZL10353) += zl10353.o | 35 | obj-$(CONFIG_DVB_ZL10353) += zl10353.o |
35 | obj-$(CONFIG_DVB_CX22702) += cx22702.o | 36 | obj-$(CONFIG_DVB_CX22702) += cx22702.o |
36 | obj-$(CONFIG_DVB_DRX397XD) += drx397xD.o | 37 | obj-$(CONFIG_DVB_DRX397XD) += drx397xD.o |
diff --git a/drivers/media/dvb/frontends/zl10039.c b/drivers/media/dvb/frontends/zl10039.c new file mode 100644 index 00000000000..11b29cb883e --- /dev/null +++ b/drivers/media/dvb/frontends/zl10039.c | |||
@@ -0,0 +1,308 @@ | |||
1 | /* | ||
2 | * Driver for Zarlink ZL10039 DVB-S tuner | ||
3 | * | ||
4 | * Copyright 2007 Jan D. Louw <jd.louw@mweb.co.za> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/module.h> | ||
23 | #include <linux/init.h> | ||
24 | #include <linux/string.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/dvb/frontend.h> | ||
27 | |||
28 | #include "dvb_frontend.h" | ||
29 | #include "zl10039.h" | ||
30 | |||
31 | static int debug; | ||
32 | |||
33 | #define dprintk(args...) \ | ||
34 | do { \ | ||
35 | if (debug) \ | ||
36 | printk(KERN_DEBUG args); \ | ||
37 | } while (0) | ||
38 | |||
39 | enum zl10039_model_id { | ||
40 | ID_ZL10039 = 1 | ||
41 | }; | ||
42 | |||
43 | struct zl10039_state { | ||
44 | struct i2c_adapter *i2c; | ||
45 | u8 i2c_addr; | ||
46 | u8 id; | ||
47 | }; | ||
48 | |||
49 | enum zl10039_reg_addr { | ||
50 | PLL0 = 0, | ||
51 | PLL1, | ||
52 | PLL2, | ||
53 | PLL3, | ||
54 | RFFE, | ||
55 | BASE0, | ||
56 | BASE1, | ||
57 | BASE2, | ||
58 | LO0, | ||
59 | LO1, | ||
60 | LO2, | ||
61 | LO3, | ||
62 | LO4, | ||
63 | LO5, | ||
64 | LO6, | ||
65 | GENERAL | ||
66 | }; | ||
67 | |||
68 | static int zl10039_read(const struct zl10039_state *state, | ||
69 | const enum zl10039_reg_addr reg, u8 *buf, | ||
70 | const size_t count) | ||
71 | { | ||
72 | u8 regbuf[] = { reg }; | ||
73 | struct i2c_msg msg[] = { | ||
74 | {/* Write register address */ | ||
75 | .addr = state->i2c_addr, | ||
76 | .flags = 0, | ||
77 | .buf = regbuf, | ||
78 | .len = 1, | ||
79 | }, {/* Read count bytes */ | ||
80 | .addr = state->i2c_addr, | ||
81 | .flags = I2C_M_RD, | ||
82 | .buf = buf, | ||
83 | .len = count, | ||
84 | }, | ||
85 | }; | ||
86 | |||
87 | dprintk("%s\n", __func__); | ||
88 | |||
89 | if (i2c_transfer(state->i2c, msg, 2) != 2) { | ||
90 | dprintk("%s: i2c read error\n", __func__); | ||
91 | return -EREMOTEIO; | ||
92 | } | ||
93 | |||
94 | return 0; /* Success */ | ||
95 | } | ||
96 | |||
97 | static int zl10039_write(struct zl10039_state *state, | ||
98 | const enum zl10039_reg_addr reg, const u8 *src, | ||
99 | const size_t count) | ||
100 | { | ||
101 | u8 buf[count + 1]; | ||
102 | struct i2c_msg msg = { | ||
103 | .addr = state->i2c_addr, | ||
104 | .flags = 0, | ||
105 | .buf = buf, | ||
106 | .len = count + 1, | ||
107 | }; | ||
108 | |||
109 | dprintk("%s\n", __func__); | ||
110 | /* Write register address and data in one go */ | ||
111 | buf[0] = reg; | ||
112 | memcpy(&buf[1], src, count); | ||
113 | if (i2c_transfer(state->i2c, &msg, 1) != 1) { | ||
114 | dprintk("%s: i2c write error\n", __func__); | ||
115 | return -EREMOTEIO; | ||
116 | } | ||
117 | |||
118 | return 0; /* Success */ | ||
119 | } | ||
120 | |||
121 | static inline int zl10039_readreg(struct zl10039_state *state, | ||
122 | const enum zl10039_reg_addr reg, u8 *val) | ||
123 | { | ||
124 | return zl10039_read(state, reg, val, 1); | ||
125 | } | ||
126 | |||
127 | static inline int zl10039_writereg(struct zl10039_state *state, | ||
128 | const enum zl10039_reg_addr reg, | ||
129 | const u8 val) | ||
130 | { | ||
131 | return zl10039_write(state, reg, &val, 1); | ||
132 | } | ||
133 | |||
134 | static int zl10039_init(struct dvb_frontend *fe) | ||
135 | { | ||
136 | struct zl10039_state *state = fe->tuner_priv; | ||
137 | int ret; | ||
138 | |||
139 | dprintk("%s\n", __func__); | ||
140 | if (fe->ops.i2c_gate_ctrl) | ||
141 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
142 | /* Reset logic */ | ||
143 | ret = zl10039_writereg(state, GENERAL, 0x40); | ||
144 | if (ret < 0) { | ||
145 | dprintk("Note: i2c write error normal when resetting the " | ||
146 | "tuner\n"); | ||
147 | } | ||
148 | /* Wake up */ | ||
149 | ret = zl10039_writereg(state, GENERAL, 0x01); | ||
150 | if (ret < 0) { | ||
151 | dprintk("Tuner power up failed\n"); | ||
152 | return ret; | ||
153 | } | ||
154 | if (fe->ops.i2c_gate_ctrl) | ||
155 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | static int zl10039_sleep(struct dvb_frontend *fe) | ||
161 | { | ||
162 | struct zl10039_state *state = fe->tuner_priv; | ||
163 | int ret; | ||
164 | |||
165 | dprintk("%s\n", __func__); | ||
166 | if (fe->ops.i2c_gate_ctrl) | ||
167 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
168 | ret = zl10039_writereg(state, GENERAL, 0x80); | ||
169 | if (ret < 0) { | ||
170 | dprintk("Tuner sleep failed\n"); | ||
171 | return ret; | ||
172 | } | ||
173 | if (fe->ops.i2c_gate_ctrl) | ||
174 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
175 | |||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | static int zl10039_set_params(struct dvb_frontend *fe, | ||
180 | struct dvb_frontend_parameters *params) | ||
181 | { | ||
182 | struct zl10039_state *state = fe->tuner_priv; | ||
183 | u8 buf[6]; | ||
184 | u8 bf; | ||
185 | u32 fbw; | ||
186 | u32 div; | ||
187 | int ret; | ||
188 | |||
189 | dprintk("%s\n", __func__); | ||
190 | dprintk("Set frequency = %d, symbol rate = %d\n", | ||
191 | params->frequency, params->u.qpsk.symbol_rate); | ||
192 | |||
193 | /* Assumed 10.111 MHz crystal oscillator */ | ||
194 | /* Cancelled num/den 80 to prevent overflow */ | ||
195 | div = (params->frequency * 1000) / 126387; | ||
196 | fbw = (params->u.qpsk.symbol_rate * 27) / 32000; | ||
197 | /* Cancelled num/den 10 to prevent overflow */ | ||
198 | bf = ((fbw * 5088) / 1011100) - 1; | ||
199 | |||
200 | /*PLL divider*/ | ||
201 | buf[0] = (div >> 8) & 0x7f; | ||
202 | buf[1] = (div >> 0) & 0xff; | ||
203 | /*Reference divider*/ | ||
204 | /* Select reference ratio of 80 */ | ||
205 | buf[2] = 0x1D; | ||
206 | /*PLL test modes*/ | ||
207 | buf[3] = 0x40; | ||
208 | /*RF Control register*/ | ||
209 | buf[4] = 0x6E; /* Bypass enable */ | ||
210 | /*Baseband filter cutoff */ | ||
211 | buf[5] = bf; | ||
212 | |||
213 | /* Open i2c gate */ | ||
214 | if (fe->ops.i2c_gate_ctrl) | ||
215 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
216 | /* BR = 10, Enable filter adjustment */ | ||
217 | ret = zl10039_writereg(state, BASE1, 0x0A); | ||
218 | if (ret < 0) | ||
219 | goto error; | ||
220 | /* Write new config values */ | ||
221 | ret = zl10039_write(state, PLL0, buf, sizeof(buf)); | ||
222 | if (ret < 0) | ||
223 | goto error; | ||
224 | /* BR = 10, Disable filter adjustment */ | ||
225 | ret = zl10039_writereg(state, BASE1, 0x6A); | ||
226 | if (ret < 0) | ||
227 | goto error; | ||
228 | |||
229 | /* Close i2c gate */ | ||
230 | if (fe->ops.i2c_gate_ctrl) | ||
231 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
232 | return 0; | ||
233 | error: | ||
234 | dprintk("Error setting tuner\n"); | ||
235 | return ret; | ||
236 | } | ||
237 | |||
238 | static int zl10039_release(struct dvb_frontend *fe) | ||
239 | { | ||
240 | struct zl10039_state *state = fe->tuner_priv; | ||
241 | |||
242 | dprintk("%s\n", __func__); | ||
243 | kfree(state); | ||
244 | fe->tuner_priv = NULL; | ||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | static struct dvb_tuner_ops zl10039_ops = { | ||
249 | .release = zl10039_release, | ||
250 | .init = zl10039_init, | ||
251 | .sleep = zl10039_sleep, | ||
252 | .set_params = zl10039_set_params, | ||
253 | }; | ||
254 | |||
255 | struct dvb_frontend *zl10039_attach(struct dvb_frontend *fe, | ||
256 | u8 i2c_addr, struct i2c_adapter *i2c) | ||
257 | { | ||
258 | struct zl10039_state *state = NULL; | ||
259 | |||
260 | dprintk("%s\n", __func__); | ||
261 | state = kmalloc(sizeof(struct zl10039_state), GFP_KERNEL); | ||
262 | if (state == NULL) | ||
263 | goto error; | ||
264 | |||
265 | state->i2c = i2c; | ||
266 | state->i2c_addr = i2c_addr; | ||
267 | |||
268 | /* Open i2c gate */ | ||
269 | if (fe->ops.i2c_gate_ctrl) | ||
270 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
271 | /* check if this is a valid tuner */ | ||
272 | if (zl10039_readreg(state, GENERAL, &state->id) < 0) { | ||
273 | /* Close i2c gate */ | ||
274 | if (fe->ops.i2c_gate_ctrl) | ||
275 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
276 | goto error; | ||
277 | } | ||
278 | /* Close i2c gate */ | ||
279 | if (fe->ops.i2c_gate_ctrl) | ||
280 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
281 | |||
282 | state->id = state->id & 0x0f; | ||
283 | switch (state->id) { | ||
284 | case ID_ZL10039: | ||
285 | strcpy(fe->ops.tuner_ops.info.name, | ||
286 | "Zarlink ZL10039 DVB-S tuner"); | ||
287 | break; | ||
288 | default: | ||
289 | dprintk("Chip ID=%x does not match a known type\n", state->id); | ||
290 | break; | ||
291 | goto error; | ||
292 | } | ||
293 | |||
294 | memcpy(&fe->ops.tuner_ops, &zl10039_ops, sizeof(struct dvb_tuner_ops)); | ||
295 | fe->tuner_priv = state; | ||
296 | dprintk("Tuner attached @ i2c address 0x%02x\n", i2c_addr); | ||
297 | return fe; | ||
298 | error: | ||
299 | kfree(state); | ||
300 | return NULL; | ||
301 | } | ||
302 | EXPORT_SYMBOL(zl10039_attach); | ||
303 | |||
304 | module_param(debug, int, 0644); | ||
305 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | ||
306 | MODULE_DESCRIPTION("Zarlink ZL10039 DVB-S tuner driver"); | ||
307 | MODULE_AUTHOR("Jan D. Louw <jd.louw@mweb.co.za>"); | ||
308 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/dvb/frontends/zl10039.h b/drivers/media/dvb/frontends/zl10039.h new file mode 100644 index 00000000000..5eee7ea162a --- /dev/null +++ b/drivers/media/dvb/frontends/zl10039.h | |||
@@ -0,0 +1,40 @@ | |||
1 | /* | ||
2 | Driver for Zarlink ZL10039 DVB-S tuner | ||
3 | |||
4 | Copyright (C) 2007 Jan D. Louw <jd.louw@mweb.co.za> | ||
5 | |||
6 | This program is free software; you can redistribute it and/or modify | ||
7 | it under the terms of the GNU General Public License as published by | ||
8 | the Free Software Foundation; either version 2 of the License, or | ||
9 | (at your option) any later version. | ||
10 | |||
11 | This program is distributed in the hope that it will be useful, | ||
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | |||
15 | GNU General Public License for more details. | ||
16 | |||
17 | You should have received a copy of the GNU General Public License | ||
18 | along with this program; if not, write to the Free Software | ||
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #ifndef ZL10039_H | ||
23 | #define ZL10039_H | ||
24 | |||
25 | #if defined(CONFIG_DVB_ZL10039) || (defined(CONFIG_DVB_ZL10039_MODULE) \ | ||
26 | && defined(MODULE)) | ||
27 | struct dvb_frontend *zl10039_attach(struct dvb_frontend *fe, | ||
28 | u8 i2c_addr, | ||
29 | struct i2c_adapter *i2c); | ||
30 | #else | ||
31 | static inline struct dvb_frontend *zl10039_attach(struct dvb_frontend *fe, | ||
32 | u8 i2c_addr, | ||
33 | struct i2c_adapter *i2c) | ||
34 | { | ||
35 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
36 | return NULL; | ||
37 | } | ||
38 | #endif /* CONFIG_DVB_ZL10039 */ | ||
39 | |||
40 | #endif /* ZL10039_H */ | ||