diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-06-14 15:35:59 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-08-13 22:40:28 -0400 |
commit | ccae7af2bf07dfef69cc2eb6ebc9e1ff15addfbd (patch) | |
tree | f33391cf2efe9038c13b88ca4049317728a7ebf0 /drivers/media/tuners | |
parent | 3785bc170f79ef04129731582b468c28e1326d6d (diff) |
[media] common: move media/common/tuners to media/tuners
Move the tuners one level up, as the "common" directory will be used
by drivers that are shared between more than one driver.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/tuners')
70 files changed, 30389 insertions, 0 deletions
diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig new file mode 100644 index 000000000000..94c6ff7a5da3 --- /dev/null +++ b/drivers/media/tuners/Kconfig | |||
@@ -0,0 +1,243 @@ | |||
1 | config MEDIA_ATTACH | ||
2 | bool "Load and attach frontend and tuner driver modules as needed" | ||
3 | depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT | ||
4 | depends on MODULES | ||
5 | default y if !EXPERT | ||
6 | help | ||
7 | Remove the static dependency of DVB card drivers on all | ||
8 | frontend modules for all possible card variants. Instead, | ||
9 | allow the card drivers to only load the frontend modules | ||
10 | they require. | ||
11 | |||
12 | Also, tuner module will automatically load a tuner driver | ||
13 | when needed, for analog mode. | ||
14 | |||
15 | This saves several KBytes of memory. | ||
16 | |||
17 | Note: You will need module-init-tools v3.2 or later for this feature. | ||
18 | |||
19 | If unsure say Y. | ||
20 | |||
21 | config MEDIA_TUNER | ||
22 | tristate | ||
23 | depends on (MEDIA_ANALOG_TV_SUPPORT || MEDIA_RADIO_SUPPORT) && I2C | ||
24 | default y | ||
25 | select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE | ||
26 | select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMISE | ||
27 | select MEDIA_TUNER_XC4000 if !MEDIA_TUNER_CUSTOMISE | ||
28 | select MEDIA_TUNER_MT20XX if !MEDIA_TUNER_CUSTOMISE | ||
29 | select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE | ||
30 | select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMISE && MEDIA_RADIO_SUPPORT && EXPERIMENTAL | ||
31 | select MEDIA_TUNER_TEA5767 if !MEDIA_TUNER_CUSTOMISE && MEDIA_RADIO_SUPPORT | ||
32 | select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE | ||
33 | select MEDIA_TUNER_TDA9887 if !MEDIA_TUNER_CUSTOMISE | ||
34 | select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE | ||
35 | |||
36 | config MEDIA_TUNER_CUSTOMISE | ||
37 | bool "Customize analog and hybrid tuner modules to build" | ||
38 | depends on MEDIA_TUNER | ||
39 | default y if EXPERT | ||
40 | help | ||
41 | This allows the user to deselect tuner drivers unnecessary | ||
42 | for their hardware from the build. Use this option with care | ||
43 | as deselecting tuner drivers which are in fact necessary will | ||
44 | result in V4L/DVB devices which cannot be tuned due to lack of | ||
45 | driver support | ||
46 | |||
47 | If unsure say N. | ||
48 | |||
49 | menu "Customize TV tuners" | ||
50 | visible if MEDIA_TUNER_CUSTOMISE | ||
51 | depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT | ||
52 | |||
53 | config MEDIA_TUNER_SIMPLE | ||
54 | tristate "Simple tuner support" | ||
55 | depends on MEDIA_SUPPORT && I2C | ||
56 | select MEDIA_TUNER_TDA9887 | ||
57 | default m if MEDIA_TUNER_CUSTOMISE | ||
58 | help | ||
59 | Say Y here to include support for various simple tuners. | ||
60 | |||
61 | config MEDIA_TUNER_TDA8290 | ||
62 | tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo" | ||
63 | depends on MEDIA_SUPPORT && I2C | ||
64 | select MEDIA_TUNER_TDA827X | ||
65 | select MEDIA_TUNER_TDA18271 | ||
66 | default m if MEDIA_TUNER_CUSTOMISE | ||
67 | help | ||
68 | Say Y here to include support for Philips TDA8290+8275(a) tuner. | ||
69 | |||
70 | config MEDIA_TUNER_TDA827X | ||
71 | tristate "Philips TDA827X silicon tuner" | ||
72 | depends on MEDIA_SUPPORT && I2C | ||
73 | default m if MEDIA_TUNER_CUSTOMISE | ||
74 | help | ||
75 | A DVB-T silicon tuner module. Say Y when you want to support this tuner. | ||
76 | |||
77 | config MEDIA_TUNER_TDA18271 | ||
78 | tristate "NXP TDA18271 silicon tuner" | ||
79 | depends on MEDIA_SUPPORT && I2C | ||
80 | default m if MEDIA_TUNER_CUSTOMISE | ||
81 | help | ||
82 | A silicon tuner module. Say Y when you want to support this tuner. | ||
83 | |||
84 | config MEDIA_TUNER_TDA9887 | ||
85 | tristate "TDA 9885/6/7 analog IF demodulator" | ||
86 | depends on MEDIA_SUPPORT && I2C | ||
87 | default m if MEDIA_TUNER_CUSTOMISE | ||
88 | help | ||
89 | Say Y here to include support for Philips TDA9885/6/7 | ||
90 | analog IF demodulator. | ||
91 | |||
92 | config MEDIA_TUNER_TEA5761 | ||
93 | tristate "TEA 5761 radio tuner (EXPERIMENTAL)" | ||
94 | depends on MEDIA_SUPPORT && I2C | ||
95 | depends on EXPERIMENTAL | ||
96 | default m if MEDIA_TUNER_CUSTOMISE | ||
97 | help | ||
98 | Say Y here to include support for the Philips TEA5761 radio tuner. | ||
99 | |||
100 | config MEDIA_TUNER_TEA5767 | ||
101 | tristate "TEA 5767 radio tuner" | ||
102 | depends on MEDIA_SUPPORT && I2C | ||
103 | default m if MEDIA_TUNER_CUSTOMISE | ||
104 | help | ||
105 | Say Y here to include support for the Philips TEA5767 radio tuner. | ||
106 | |||
107 | config MEDIA_TUNER_MT20XX | ||
108 | tristate "Microtune 2032 / 2050 tuners" | ||
109 | depends on MEDIA_SUPPORT && I2C | ||
110 | default m if MEDIA_TUNER_CUSTOMISE | ||
111 | help | ||
112 | Say Y here to include support for the MT2032 / MT2050 tuner. | ||
113 | |||
114 | config MEDIA_TUNER_MT2060 | ||
115 | tristate "Microtune MT2060 silicon IF tuner" | ||
116 | depends on MEDIA_SUPPORT && I2C | ||
117 | default m if MEDIA_TUNER_CUSTOMISE | ||
118 | help | ||
119 | A driver for the silicon IF tuner MT2060 from Microtune. | ||
120 | |||
121 | config MEDIA_TUNER_MT2063 | ||
122 | tristate "Microtune MT2063 silicon IF tuner" | ||
123 | depends on MEDIA_SUPPORT && I2C | ||
124 | default m if MEDIA_TUNER_CUSTOMISE | ||
125 | help | ||
126 | A driver for the silicon IF tuner MT2063 from Microtune. | ||
127 | |||
128 | config MEDIA_TUNER_MT2266 | ||
129 | tristate "Microtune MT2266 silicon tuner" | ||
130 | depends on MEDIA_SUPPORT && I2C | ||
131 | default m if MEDIA_TUNER_CUSTOMISE | ||
132 | help | ||
133 | A driver for the silicon baseband tuner MT2266 from Microtune. | ||
134 | |||
135 | config MEDIA_TUNER_MT2131 | ||
136 | tristate "Microtune MT2131 silicon tuner" | ||
137 | depends on MEDIA_SUPPORT && I2C | ||
138 | default m if MEDIA_TUNER_CUSTOMISE | ||
139 | help | ||
140 | A driver for the silicon baseband tuner MT2131 from Microtune. | ||
141 | |||
142 | config MEDIA_TUNER_QT1010 | ||
143 | tristate "Quantek QT1010 silicon tuner" | ||
144 | depends on MEDIA_SUPPORT && I2C | ||
145 | default m if MEDIA_TUNER_CUSTOMISE | ||
146 | help | ||
147 | A driver for the silicon tuner QT1010 from Quantek. | ||
148 | |||
149 | config MEDIA_TUNER_XC2028 | ||
150 | tristate "XCeive xc2028/xc3028 tuners" | ||
151 | depends on MEDIA_SUPPORT && I2C | ||
152 | default m if MEDIA_TUNER_CUSTOMISE | ||
153 | help | ||
154 | Say Y here to include support for the xc2028/xc3028 tuners. | ||
155 | |||
156 | config MEDIA_TUNER_XC5000 | ||
157 | tristate "Xceive XC5000 silicon tuner" | ||
158 | depends on MEDIA_SUPPORT && I2C | ||
159 | default m if MEDIA_TUNER_CUSTOMISE | ||
160 | help | ||
161 | A driver for the silicon tuner XC5000 from Xceive. | ||
162 | This device is only used inside a SiP called together with a | ||
163 | demodulator for now. | ||
164 | |||
165 | config MEDIA_TUNER_XC4000 | ||
166 | tristate "Xceive XC4000 silicon tuner" | ||
167 | depends on MEDIA_SUPPORT && I2C | ||
168 | default m if MEDIA_TUNER_CUSTOMISE | ||
169 | help | ||
170 | A driver for the silicon tuner XC4000 from Xceive. | ||
171 | This device is only used inside a SiP called together with a | ||
172 | demodulator for now. | ||
173 | |||
174 | config MEDIA_TUNER_MXL5005S | ||
175 | tristate "MaxLinear MSL5005S silicon tuner" | ||
176 | depends on MEDIA_SUPPORT && I2C | ||
177 | default m if MEDIA_TUNER_CUSTOMISE | ||
178 | help | ||
179 | A driver for the silicon tuner MXL5005S from MaxLinear. | ||
180 | |||
181 | config MEDIA_TUNER_MXL5007T | ||
182 | tristate "MaxLinear MxL5007T silicon tuner" | ||
183 | depends on MEDIA_SUPPORT && I2C | ||
184 | default m if MEDIA_TUNER_CUSTOMISE | ||
185 | help | ||
186 | A driver for the silicon tuner MxL5007T from MaxLinear. | ||
187 | |||
188 | config MEDIA_TUNER_MC44S803 | ||
189 | tristate "Freescale MC44S803 Low Power CMOS Broadband tuners" | ||
190 | depends on MEDIA_SUPPORT && I2C | ||
191 | default m if MEDIA_TUNER_CUSTOMISE | ||
192 | help | ||
193 | Say Y here to support the Freescale MC44S803 based tuners | ||
194 | |||
195 | config MEDIA_TUNER_MAX2165 | ||
196 | tristate "Maxim MAX2165 silicon tuner" | ||
197 | depends on MEDIA_SUPPORT && I2C | ||
198 | default m if MEDIA_TUNER_CUSTOMISE | ||
199 | help | ||
200 | A driver for the silicon tuner MAX2165 from Maxim. | ||
201 | |||
202 | config MEDIA_TUNER_TDA18218 | ||
203 | tristate "NXP TDA18218 silicon tuner" | ||
204 | depends on MEDIA_SUPPORT && I2C | ||
205 | default m if MEDIA_TUNER_CUSTOMISE | ||
206 | help | ||
207 | NXP TDA18218 silicon tuner driver. | ||
208 | |||
209 | config MEDIA_TUNER_FC0011 | ||
210 | tristate "Fitipower FC0011 silicon tuner" | ||
211 | depends on MEDIA_SUPPORT && I2C | ||
212 | default m if MEDIA_TUNER_CUSTOMISE | ||
213 | help | ||
214 | Fitipower FC0011 silicon tuner driver. | ||
215 | |||
216 | config MEDIA_TUNER_FC0012 | ||
217 | tristate "Fitipower FC0012 silicon tuner" | ||
218 | depends on MEDIA_SUPPORT && I2C | ||
219 | default m if MEDIA_TUNER_CUSTOMISE | ||
220 | help | ||
221 | Fitipower FC0012 silicon tuner driver. | ||
222 | |||
223 | config MEDIA_TUNER_FC0013 | ||
224 | tristate "Fitipower FC0013 silicon tuner" | ||
225 | depends on MEDIA_SUPPORT && I2C | ||
226 | default m if MEDIA_TUNER_CUSTOMISE | ||
227 | help | ||
228 | Fitipower FC0013 silicon tuner driver. | ||
229 | |||
230 | config MEDIA_TUNER_TDA18212 | ||
231 | tristate "NXP TDA18212 silicon tuner" | ||
232 | depends on MEDIA_SUPPORT && I2C | ||
233 | default m if MEDIA_TUNER_CUSTOMISE | ||
234 | help | ||
235 | NXP TDA18212 silicon tuner driver. | ||
236 | |||
237 | config MEDIA_TUNER_TUA9001 | ||
238 | tristate "Infineon TUA 9001 silicon tuner" | ||
239 | depends on MEDIA_SUPPORT && I2C | ||
240 | default m if MEDIA_TUNER_CUSTOMISE | ||
241 | help | ||
242 | Infineon TUA 9001 silicon tuner driver. | ||
243 | endmenu | ||
diff --git a/drivers/media/tuners/Makefile b/drivers/media/tuners/Makefile new file mode 100644 index 000000000000..112aeee90202 --- /dev/null +++ b/drivers/media/tuners/Makefile | |||
@@ -0,0 +1,37 @@ | |||
1 | # | ||
2 | # Makefile for common V4L/DVB tuners | ||
3 | # | ||
4 | |||
5 | tda18271-objs := tda18271-maps.o tda18271-common.o tda18271-fe.o | ||
6 | |||
7 | obj-$(CONFIG_MEDIA_TUNER_XC2028) += tuner-xc2028.o | ||
8 | obj-$(CONFIG_MEDIA_TUNER_SIMPLE) += tuner-simple.o | ||
9 | # tuner-types will be merged into tuner-simple, in the future | ||
10 | obj-$(CONFIG_MEDIA_TUNER_SIMPLE) += tuner-types.o | ||
11 | obj-$(CONFIG_MEDIA_TUNER_MT20XX) += mt20xx.o | ||
12 | obj-$(CONFIG_MEDIA_TUNER_TDA8290) += tda8290.o | ||
13 | obj-$(CONFIG_MEDIA_TUNER_TEA5767) += tea5767.o | ||
14 | obj-$(CONFIG_MEDIA_TUNER_TEA5761) += tea5761.o | ||
15 | obj-$(CONFIG_MEDIA_TUNER_TDA9887) += tda9887.o | ||
16 | obj-$(CONFIG_MEDIA_TUNER_TDA827X) += tda827x.o | ||
17 | obj-$(CONFIG_MEDIA_TUNER_TDA18271) += tda18271.o | ||
18 | obj-$(CONFIG_MEDIA_TUNER_XC5000) += xc5000.o | ||
19 | obj-$(CONFIG_MEDIA_TUNER_XC4000) += xc4000.o | ||
20 | obj-$(CONFIG_MEDIA_TUNER_MT2060) += mt2060.o | ||
21 | obj-$(CONFIG_MEDIA_TUNER_MT2063) += mt2063.o | ||
22 | obj-$(CONFIG_MEDIA_TUNER_MT2266) += mt2266.o | ||
23 | obj-$(CONFIG_MEDIA_TUNER_QT1010) += qt1010.o | ||
24 | obj-$(CONFIG_MEDIA_TUNER_MT2131) += mt2131.o | ||
25 | obj-$(CONFIG_MEDIA_TUNER_MXL5005S) += mxl5005s.o | ||
26 | obj-$(CONFIG_MEDIA_TUNER_MXL5007T) += mxl5007t.o | ||
27 | obj-$(CONFIG_MEDIA_TUNER_MC44S803) += mc44s803.o | ||
28 | obj-$(CONFIG_MEDIA_TUNER_MAX2165) += max2165.o | ||
29 | obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o | ||
30 | obj-$(CONFIG_MEDIA_TUNER_TDA18212) += tda18212.o | ||
31 | obj-$(CONFIG_MEDIA_TUNER_TUA9001) += tua9001.o | ||
32 | obj-$(CONFIG_MEDIA_TUNER_FC0011) += fc0011.o | ||
33 | obj-$(CONFIG_MEDIA_TUNER_FC0012) += fc0012.o | ||
34 | obj-$(CONFIG_MEDIA_TUNER_FC0013) += fc0013.o | ||
35 | |||
36 | ccflags-y += -I$(srctree)/drivers/media/dvb-core | ||
37 | ccflags-y += -I$(srctree)/drivers/media/dvb-frontends | ||
diff --git a/drivers/media/tuners/fc0011.c b/drivers/media/tuners/fc0011.c new file mode 100644 index 000000000000..e4882546c283 --- /dev/null +++ b/drivers/media/tuners/fc0011.c | |||
@@ -0,0 +1,524 @@ | |||
1 | /* | ||
2 | * Fitipower FC0011 tuner driver | ||
3 | * | ||
4 | * Copyright (C) 2012 Michael Buesch <m@bues.ch> | ||
5 | * | ||
6 | * Derived from FC0012 tuner driver: | ||
7 | * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | */ | ||
23 | |||
24 | #include "fc0011.h" | ||
25 | |||
26 | |||
27 | /* Tuner registers */ | ||
28 | enum { | ||
29 | FC11_REG_0, | ||
30 | FC11_REG_FA, /* FA */ | ||
31 | FC11_REG_FP, /* FP */ | ||
32 | FC11_REG_XINHI, /* XIN high 8 bit */ | ||
33 | FC11_REG_XINLO, /* XIN low 8 bit */ | ||
34 | FC11_REG_VCO, /* VCO */ | ||
35 | FC11_REG_VCOSEL, /* VCO select */ | ||
36 | FC11_REG_7, /* Unknown tuner reg 7 */ | ||
37 | FC11_REG_8, /* Unknown tuner reg 8 */ | ||
38 | FC11_REG_9, | ||
39 | FC11_REG_10, /* Unknown tuner reg 10 */ | ||
40 | FC11_REG_11, /* Unknown tuner reg 11 */ | ||
41 | FC11_REG_12, | ||
42 | FC11_REG_RCCAL, /* RC calibrate */ | ||
43 | FC11_REG_VCOCAL, /* VCO calibrate */ | ||
44 | FC11_REG_15, | ||
45 | FC11_REG_16, /* Unknown tuner reg 16 */ | ||
46 | FC11_REG_17, | ||
47 | |||
48 | FC11_NR_REGS, /* Number of registers */ | ||
49 | }; | ||
50 | |||
51 | enum FC11_REG_VCOSEL_bits { | ||
52 | FC11_VCOSEL_2 = 0x08, /* VCO select 2 */ | ||
53 | FC11_VCOSEL_1 = 0x10, /* VCO select 1 */ | ||
54 | FC11_VCOSEL_CLKOUT = 0x20, /* Fix clock out */ | ||
55 | FC11_VCOSEL_BW7M = 0x40, /* 7MHz bw */ | ||
56 | FC11_VCOSEL_BW6M = 0x80, /* 6MHz bw */ | ||
57 | }; | ||
58 | |||
59 | enum FC11_REG_RCCAL_bits { | ||
60 | FC11_RCCAL_FORCE = 0x10, /* force */ | ||
61 | }; | ||
62 | |||
63 | enum FC11_REG_VCOCAL_bits { | ||
64 | FC11_VCOCAL_RUN = 0, /* VCO calibration run */ | ||
65 | FC11_VCOCAL_VALUEMASK = 0x3F, /* VCO calibration value mask */ | ||
66 | FC11_VCOCAL_OK = 0x40, /* VCO calibration Ok */ | ||
67 | FC11_VCOCAL_RESET = 0x80, /* VCO calibration reset */ | ||
68 | }; | ||
69 | |||
70 | |||
71 | struct fc0011_priv { | ||
72 | struct i2c_adapter *i2c; | ||
73 | u8 addr; | ||
74 | |||
75 | u32 frequency; | ||
76 | u32 bandwidth; | ||
77 | }; | ||
78 | |||
79 | |||
80 | static int fc0011_writereg(struct fc0011_priv *priv, u8 reg, u8 val) | ||
81 | { | ||
82 | u8 buf[2] = { reg, val }; | ||
83 | struct i2c_msg msg = { .addr = priv->addr, | ||
84 | .flags = 0, .buf = buf, .len = 2 }; | ||
85 | |||
86 | if (i2c_transfer(priv->i2c, &msg, 1) != 1) { | ||
87 | dev_err(&priv->i2c->dev, | ||
88 | "I2C write reg failed, reg: %02x, val: %02x\n", | ||
89 | reg, val); | ||
90 | return -EIO; | ||
91 | } | ||
92 | |||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | static int fc0011_readreg(struct fc0011_priv *priv, u8 reg, u8 *val) | ||
97 | { | ||
98 | u8 dummy; | ||
99 | struct i2c_msg msg[2] = { | ||
100 | { .addr = priv->addr, | ||
101 | .flags = 0, .buf = ®, .len = 1 }, | ||
102 | { .addr = priv->addr, | ||
103 | .flags = I2C_M_RD, .buf = val ? : &dummy, .len = 1 }, | ||
104 | }; | ||
105 | |||
106 | if (i2c_transfer(priv->i2c, msg, 2) != 2) { | ||
107 | dev_err(&priv->i2c->dev, | ||
108 | "I2C read failed, reg: %02x\n", reg); | ||
109 | return -EIO; | ||
110 | } | ||
111 | |||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | static int fc0011_release(struct dvb_frontend *fe) | ||
116 | { | ||
117 | kfree(fe->tuner_priv); | ||
118 | fe->tuner_priv = NULL; | ||
119 | |||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | static int fc0011_init(struct dvb_frontend *fe) | ||
124 | { | ||
125 | struct fc0011_priv *priv = fe->tuner_priv; | ||
126 | int err; | ||
127 | |||
128 | if (WARN_ON(!fe->callback)) | ||
129 | return -EINVAL; | ||
130 | |||
131 | err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, | ||
132 | FC0011_FE_CALLBACK_POWER, priv->addr); | ||
133 | if (err) { | ||
134 | dev_err(&priv->i2c->dev, "Power-on callback failed\n"); | ||
135 | return err; | ||
136 | } | ||
137 | err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, | ||
138 | FC0011_FE_CALLBACK_RESET, priv->addr); | ||
139 | if (err) { | ||
140 | dev_err(&priv->i2c->dev, "Reset callback failed\n"); | ||
141 | return err; | ||
142 | } | ||
143 | |||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | /* Initiate VCO calibration */ | ||
148 | static int fc0011_vcocal_trigger(struct fc0011_priv *priv) | ||
149 | { | ||
150 | int err; | ||
151 | |||
152 | err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RESET); | ||
153 | if (err) | ||
154 | return err; | ||
155 | err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RUN); | ||
156 | if (err) | ||
157 | return err; | ||
158 | |||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | /* Read VCO calibration value */ | ||
163 | static int fc0011_vcocal_read(struct fc0011_priv *priv, u8 *value) | ||
164 | { | ||
165 | int err; | ||
166 | |||
167 | err = fc0011_writereg(priv, FC11_REG_VCOCAL, FC11_VCOCAL_RUN); | ||
168 | if (err) | ||
169 | return err; | ||
170 | usleep_range(10000, 20000); | ||
171 | err = fc0011_readreg(priv, FC11_REG_VCOCAL, value); | ||
172 | if (err) | ||
173 | return err; | ||
174 | |||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | static int fc0011_set_params(struct dvb_frontend *fe) | ||
179 | { | ||
180 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; | ||
181 | struct fc0011_priv *priv = fe->tuner_priv; | ||
182 | int err; | ||
183 | unsigned int i, vco_retries; | ||
184 | u32 freq = p->frequency / 1000; | ||
185 | u32 bandwidth = p->bandwidth_hz / 1000; | ||
186 | u32 fvco, xin, xdiv, xdivr; | ||
187 | u16 frac; | ||
188 | u8 fa, fp, vco_sel, vco_cal; | ||
189 | u8 regs[FC11_NR_REGS] = { }; | ||
190 | |||
191 | regs[FC11_REG_7] = 0x0F; | ||
192 | regs[FC11_REG_8] = 0x3E; | ||
193 | regs[FC11_REG_10] = 0xB8; | ||
194 | regs[FC11_REG_11] = 0x80; | ||
195 | regs[FC11_REG_RCCAL] = 0x04; | ||
196 | err = fc0011_writereg(priv, FC11_REG_7, regs[FC11_REG_7]); | ||
197 | err |= fc0011_writereg(priv, FC11_REG_8, regs[FC11_REG_8]); | ||
198 | err |= fc0011_writereg(priv, FC11_REG_10, regs[FC11_REG_10]); | ||
199 | err |= fc0011_writereg(priv, FC11_REG_11, regs[FC11_REG_11]); | ||
200 | err |= fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]); | ||
201 | if (err) | ||
202 | return -EIO; | ||
203 | |||
204 | /* Set VCO freq and VCO div */ | ||
205 | if (freq < 54000) { | ||
206 | fvco = freq * 64; | ||
207 | regs[FC11_REG_VCO] = 0x82; | ||
208 | } else if (freq < 108000) { | ||
209 | fvco = freq * 32; | ||
210 | regs[FC11_REG_VCO] = 0x42; | ||
211 | } else if (freq < 216000) { | ||
212 | fvco = freq * 16; | ||
213 | regs[FC11_REG_VCO] = 0x22; | ||
214 | } else if (freq < 432000) { | ||
215 | fvco = freq * 8; | ||
216 | regs[FC11_REG_VCO] = 0x12; | ||
217 | } else { | ||
218 | fvco = freq * 4; | ||
219 | regs[FC11_REG_VCO] = 0x0A; | ||
220 | } | ||
221 | |||
222 | /* Calc XIN. The PLL reference frequency is 18 MHz. */ | ||
223 | xdiv = fvco / 18000; | ||
224 | frac = fvco - xdiv * 18000; | ||
225 | frac = (frac << 15) / 18000; | ||
226 | if (frac >= 16384) | ||
227 | frac += 32786; | ||
228 | if (!frac) | ||
229 | xin = 0; | ||
230 | else if (frac < 511) | ||
231 | xin = 512; | ||
232 | else if (frac < 65026) | ||
233 | xin = frac; | ||
234 | else | ||
235 | xin = 65024; | ||
236 | regs[FC11_REG_XINHI] = xin >> 8; | ||
237 | regs[FC11_REG_XINLO] = xin; | ||
238 | |||
239 | /* Calc FP and FA */ | ||
240 | xdivr = xdiv; | ||
241 | if (fvco - xdiv * 18000 >= 9000) | ||
242 | xdivr += 1; /* round */ | ||
243 | fp = xdivr / 8; | ||
244 | fa = xdivr - fp * 8; | ||
245 | if (fa < 2) { | ||
246 | fp -= 1; | ||
247 | fa += 8; | ||
248 | } | ||
249 | if (fp > 0x1F) { | ||
250 | fp &= 0x1F; | ||
251 | fa &= 0xF; | ||
252 | } | ||
253 | if (fa >= fp) { | ||
254 | dev_warn(&priv->i2c->dev, | ||
255 | "fa %02X >= fp %02X, but trying to continue\n", | ||
256 | (unsigned int)(u8)fa, (unsigned int)(u8)fp); | ||
257 | } | ||
258 | regs[FC11_REG_FA] = fa; | ||
259 | regs[FC11_REG_FP] = fp; | ||
260 | |||
261 | /* Select bandwidth */ | ||
262 | switch (bandwidth) { | ||
263 | case 8000: | ||
264 | break; | ||
265 | case 7000: | ||
266 | regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_BW7M; | ||
267 | break; | ||
268 | default: | ||
269 | dev_warn(&priv->i2c->dev, "Unsupported bandwidth %u kHz. " | ||
270 | "Using 6000 kHz.\n", | ||
271 | bandwidth); | ||
272 | bandwidth = 6000; | ||
273 | /* fallthrough */ | ||
274 | case 6000: | ||
275 | regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_BW6M; | ||
276 | break; | ||
277 | } | ||
278 | |||
279 | /* Pre VCO select */ | ||
280 | if (fvco < 2320000) { | ||
281 | vco_sel = 0; | ||
282 | regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); | ||
283 | } else if (fvco < 3080000) { | ||
284 | vco_sel = 1; | ||
285 | regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); | ||
286 | regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1; | ||
287 | } else { | ||
288 | vco_sel = 2; | ||
289 | regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); | ||
290 | regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2; | ||
291 | } | ||
292 | |||
293 | /* Fix for low freqs */ | ||
294 | if (freq < 45000) { | ||
295 | regs[FC11_REG_FA] = 0x6; | ||
296 | regs[FC11_REG_FP] = 0x11; | ||
297 | } | ||
298 | |||
299 | /* Clock out fix */ | ||
300 | regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_CLKOUT; | ||
301 | |||
302 | /* Write the cached registers */ | ||
303 | for (i = FC11_REG_FA; i <= FC11_REG_VCOSEL; i++) { | ||
304 | err = fc0011_writereg(priv, i, regs[i]); | ||
305 | if (err) | ||
306 | return err; | ||
307 | } | ||
308 | |||
309 | /* VCO calibration */ | ||
310 | err = fc0011_vcocal_trigger(priv); | ||
311 | if (err) | ||
312 | return err; | ||
313 | err = fc0011_vcocal_read(priv, &vco_cal); | ||
314 | if (err) | ||
315 | return err; | ||
316 | vco_retries = 0; | ||
317 | while (!(vco_cal & FC11_VCOCAL_OK) && vco_retries < 3) { | ||
318 | /* Reset the tuner and try again */ | ||
319 | err = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, | ||
320 | FC0011_FE_CALLBACK_RESET, priv->addr); | ||
321 | if (err) { | ||
322 | dev_err(&priv->i2c->dev, "Failed to reset tuner\n"); | ||
323 | return err; | ||
324 | } | ||
325 | /* Reinit tuner config */ | ||
326 | err = 0; | ||
327 | for (i = FC11_REG_FA; i <= FC11_REG_VCOSEL; i++) | ||
328 | err |= fc0011_writereg(priv, i, regs[i]); | ||
329 | err |= fc0011_writereg(priv, FC11_REG_7, regs[FC11_REG_7]); | ||
330 | err |= fc0011_writereg(priv, FC11_REG_8, regs[FC11_REG_8]); | ||
331 | err |= fc0011_writereg(priv, FC11_REG_10, regs[FC11_REG_10]); | ||
332 | err |= fc0011_writereg(priv, FC11_REG_11, regs[FC11_REG_11]); | ||
333 | err |= fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]); | ||
334 | if (err) | ||
335 | return -EIO; | ||
336 | /* VCO calibration */ | ||
337 | err = fc0011_vcocal_trigger(priv); | ||
338 | if (err) | ||
339 | return err; | ||
340 | err = fc0011_vcocal_read(priv, &vco_cal); | ||
341 | if (err) | ||
342 | return err; | ||
343 | vco_retries++; | ||
344 | } | ||
345 | if (!(vco_cal & FC11_VCOCAL_OK)) { | ||
346 | dev_err(&priv->i2c->dev, | ||
347 | "Failed to read VCO calibration value (got %02X)\n", | ||
348 | (unsigned int)vco_cal); | ||
349 | return -EIO; | ||
350 | } | ||
351 | vco_cal &= FC11_VCOCAL_VALUEMASK; | ||
352 | |||
353 | switch (vco_sel) { | ||
354 | case 0: | ||
355 | if (vco_cal < 8) { | ||
356 | regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); | ||
357 | regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1; | ||
358 | err = fc0011_writereg(priv, FC11_REG_VCOSEL, | ||
359 | regs[FC11_REG_VCOSEL]); | ||
360 | if (err) | ||
361 | return err; | ||
362 | err = fc0011_vcocal_trigger(priv); | ||
363 | if (err) | ||
364 | return err; | ||
365 | } else { | ||
366 | regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); | ||
367 | err = fc0011_writereg(priv, FC11_REG_VCOSEL, | ||
368 | regs[FC11_REG_VCOSEL]); | ||
369 | if (err) | ||
370 | return err; | ||
371 | } | ||
372 | break; | ||
373 | case 1: | ||
374 | if (vco_cal < 5) { | ||
375 | regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); | ||
376 | regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2; | ||
377 | err = fc0011_writereg(priv, FC11_REG_VCOSEL, | ||
378 | regs[FC11_REG_VCOSEL]); | ||
379 | if (err) | ||
380 | return err; | ||
381 | err = fc0011_vcocal_trigger(priv); | ||
382 | if (err) | ||
383 | return err; | ||
384 | } else if (vco_cal <= 48) { | ||
385 | regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); | ||
386 | regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1; | ||
387 | err = fc0011_writereg(priv, FC11_REG_VCOSEL, | ||
388 | regs[FC11_REG_VCOSEL]); | ||
389 | if (err) | ||
390 | return err; | ||
391 | } else { | ||
392 | regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); | ||
393 | err = fc0011_writereg(priv, FC11_REG_VCOSEL, | ||
394 | regs[FC11_REG_VCOSEL]); | ||
395 | if (err) | ||
396 | return err; | ||
397 | err = fc0011_vcocal_trigger(priv); | ||
398 | if (err) | ||
399 | return err; | ||
400 | } | ||
401 | break; | ||
402 | case 2: | ||
403 | if (vco_cal > 53) { | ||
404 | regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); | ||
405 | regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_1; | ||
406 | err = fc0011_writereg(priv, FC11_REG_VCOSEL, | ||
407 | regs[FC11_REG_VCOSEL]); | ||
408 | if (err) | ||
409 | return err; | ||
410 | err = fc0011_vcocal_trigger(priv); | ||
411 | if (err) | ||
412 | return err; | ||
413 | } else { | ||
414 | regs[FC11_REG_VCOSEL] &= ~(FC11_VCOSEL_1 | FC11_VCOSEL_2); | ||
415 | regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_2; | ||
416 | err = fc0011_writereg(priv, FC11_REG_VCOSEL, | ||
417 | regs[FC11_REG_VCOSEL]); | ||
418 | if (err) | ||
419 | return err; | ||
420 | } | ||
421 | break; | ||
422 | } | ||
423 | err = fc0011_vcocal_read(priv, NULL); | ||
424 | if (err) | ||
425 | return err; | ||
426 | usleep_range(10000, 50000); | ||
427 | |||
428 | err = fc0011_readreg(priv, FC11_REG_RCCAL, ®s[FC11_REG_RCCAL]); | ||
429 | if (err) | ||
430 | return err; | ||
431 | regs[FC11_REG_RCCAL] |= FC11_RCCAL_FORCE; | ||
432 | err = fc0011_writereg(priv, FC11_REG_RCCAL, regs[FC11_REG_RCCAL]); | ||
433 | if (err) | ||
434 | return err; | ||
435 | err = fc0011_writereg(priv, FC11_REG_16, 0xB); | ||
436 | if (err) | ||
437 | return err; | ||
438 | |||
439 | dev_dbg(&priv->i2c->dev, "Tuned to " | ||
440 | "fa=%02X fp=%02X xin=%02X%02X vco=%02X vcosel=%02X " | ||
441 | "vcocal=%02X(%u) bw=%u\n", | ||
442 | (unsigned int)regs[FC11_REG_FA], | ||
443 | (unsigned int)regs[FC11_REG_FP], | ||
444 | (unsigned int)regs[FC11_REG_XINHI], | ||
445 | (unsigned int)regs[FC11_REG_XINLO], | ||
446 | (unsigned int)regs[FC11_REG_VCO], | ||
447 | (unsigned int)regs[FC11_REG_VCOSEL], | ||
448 | (unsigned int)vco_cal, vco_retries, | ||
449 | (unsigned int)bandwidth); | ||
450 | |||
451 | priv->frequency = p->frequency; | ||
452 | priv->bandwidth = p->bandwidth_hz; | ||
453 | |||
454 | return 0; | ||
455 | } | ||
456 | |||
457 | static int fc0011_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
458 | { | ||
459 | struct fc0011_priv *priv = fe->tuner_priv; | ||
460 | |||
461 | *frequency = priv->frequency; | ||
462 | |||
463 | return 0; | ||
464 | } | ||
465 | |||
466 | static int fc0011_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
467 | { | ||
468 | *frequency = 0; | ||
469 | |||
470 | return 0; | ||
471 | } | ||
472 | |||
473 | static int fc0011_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) | ||
474 | { | ||
475 | struct fc0011_priv *priv = fe->tuner_priv; | ||
476 | |||
477 | *bandwidth = priv->bandwidth; | ||
478 | |||
479 | return 0; | ||
480 | } | ||
481 | |||
482 | static const struct dvb_tuner_ops fc0011_tuner_ops = { | ||
483 | .info = { | ||
484 | .name = "Fitipower FC0011", | ||
485 | |||
486 | .frequency_min = 45000000, | ||
487 | .frequency_max = 1000000000, | ||
488 | }, | ||
489 | |||
490 | .release = fc0011_release, | ||
491 | .init = fc0011_init, | ||
492 | |||
493 | .set_params = fc0011_set_params, | ||
494 | |||
495 | .get_frequency = fc0011_get_frequency, | ||
496 | .get_if_frequency = fc0011_get_if_frequency, | ||
497 | .get_bandwidth = fc0011_get_bandwidth, | ||
498 | }; | ||
499 | |||
500 | struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe, | ||
501 | struct i2c_adapter *i2c, | ||
502 | const struct fc0011_config *config) | ||
503 | { | ||
504 | struct fc0011_priv *priv; | ||
505 | |||
506 | priv = kzalloc(sizeof(struct fc0011_priv), GFP_KERNEL); | ||
507 | if (!priv) | ||
508 | return NULL; | ||
509 | |||
510 | priv->i2c = i2c; | ||
511 | priv->addr = config->i2c_address; | ||
512 | |||
513 | fe->tuner_priv = priv; | ||
514 | fe->ops.tuner_ops = fc0011_tuner_ops; | ||
515 | |||
516 | dev_info(&priv->i2c->dev, "Fitipower FC0011 tuner attached\n"); | ||
517 | |||
518 | return fe; | ||
519 | } | ||
520 | EXPORT_SYMBOL(fc0011_attach); | ||
521 | |||
522 | MODULE_DESCRIPTION("Fitipower FC0011 silicon tuner driver"); | ||
523 | MODULE_AUTHOR("Michael Buesch <m@bues.ch>"); | ||
524 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/tuners/fc0011.h b/drivers/media/tuners/fc0011.h new file mode 100644 index 000000000000..0ee581f122d2 --- /dev/null +++ b/drivers/media/tuners/fc0011.h | |||
@@ -0,0 +1,41 @@ | |||
1 | #ifndef LINUX_FC0011_H_ | ||
2 | #define LINUX_FC0011_H_ | ||
3 | |||
4 | #include "dvb_frontend.h" | ||
5 | |||
6 | |||
7 | /** struct fc0011_config - fc0011 hardware config | ||
8 | * | ||
9 | * @i2c_address: I2C bus address. | ||
10 | */ | ||
11 | struct fc0011_config { | ||
12 | u8 i2c_address; | ||
13 | }; | ||
14 | |||
15 | /** enum fc0011_fe_callback_commands - Frontend callbacks | ||
16 | * | ||
17 | * @FC0011_FE_CALLBACK_POWER: Power on tuner hardware. | ||
18 | * @FC0011_FE_CALLBACK_RESET: Request a tuner reset. | ||
19 | */ | ||
20 | enum fc0011_fe_callback_commands { | ||
21 | FC0011_FE_CALLBACK_POWER, | ||
22 | FC0011_FE_CALLBACK_RESET, | ||
23 | }; | ||
24 | |||
25 | #if defined(CONFIG_MEDIA_TUNER_FC0011) ||\ | ||
26 | defined(CONFIG_MEDIA_TUNER_FC0011_MODULE) | ||
27 | struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe, | ||
28 | struct i2c_adapter *i2c, | ||
29 | const struct fc0011_config *config); | ||
30 | #else | ||
31 | static inline | ||
32 | struct dvb_frontend *fc0011_attach(struct dvb_frontend *fe, | ||
33 | struct i2c_adapter *i2c, | ||
34 | const struct fc0011_config *config) | ||
35 | { | ||
36 | dev_err(&i2c->dev, "fc0011 driver disabled in Kconfig\n"); | ||
37 | return NULL; | ||
38 | } | ||
39 | #endif | ||
40 | |||
41 | #endif /* LINUX_FC0011_H_ */ | ||
diff --git a/drivers/media/tuners/fc0012-priv.h b/drivers/media/tuners/fc0012-priv.h new file mode 100644 index 000000000000..4577c917e616 --- /dev/null +++ b/drivers/media/tuners/fc0012-priv.h | |||
@@ -0,0 +1,43 @@ | |||
1 | /* | ||
2 | * Fitipower FC0012 tuner driver - private includes | ||
3 | * | ||
4 | * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net> | ||
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 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef _FC0012_PRIV_H_ | ||
22 | #define _FC0012_PRIV_H_ | ||
23 | |||
24 | #define LOG_PREFIX "fc0012" | ||
25 | |||
26 | #undef err | ||
27 | #define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) | ||
28 | #undef info | ||
29 | #define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) | ||
30 | #undef warn | ||
31 | #define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) | ||
32 | |||
33 | struct fc0012_priv { | ||
34 | struct i2c_adapter *i2c; | ||
35 | u8 addr; | ||
36 | u8 dual_master; | ||
37 | u8 xtal_freq; | ||
38 | |||
39 | u32 frequency; | ||
40 | u32 bandwidth; | ||
41 | }; | ||
42 | |||
43 | #endif | ||
diff --git a/drivers/media/tuners/fc0012.c b/drivers/media/tuners/fc0012.c new file mode 100644 index 000000000000..308135abd54c --- /dev/null +++ b/drivers/media/tuners/fc0012.c | |||
@@ -0,0 +1,467 @@ | |||
1 | /* | ||
2 | * Fitipower FC0012 tuner driver | ||
3 | * | ||
4 | * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net> | ||
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 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #include "fc0012.h" | ||
22 | #include "fc0012-priv.h" | ||
23 | |||
24 | static int fc0012_writereg(struct fc0012_priv *priv, u8 reg, u8 val) | ||
25 | { | ||
26 | u8 buf[2] = {reg, val}; | ||
27 | struct i2c_msg msg = { | ||
28 | .addr = priv->addr, .flags = 0, .buf = buf, .len = 2 | ||
29 | }; | ||
30 | |||
31 | if (i2c_transfer(priv->i2c, &msg, 1) != 1) { | ||
32 | err("I2C write reg failed, reg: %02x, val: %02x", reg, val); | ||
33 | return -EREMOTEIO; | ||
34 | } | ||
35 | return 0; | ||
36 | } | ||
37 | |||
38 | static int fc0012_readreg(struct fc0012_priv *priv, u8 reg, u8 *val) | ||
39 | { | ||
40 | struct i2c_msg msg[2] = { | ||
41 | { .addr = priv->addr, .flags = 0, .buf = ®, .len = 1 }, | ||
42 | { .addr = priv->addr, .flags = I2C_M_RD, .buf = val, .len = 1 }, | ||
43 | }; | ||
44 | |||
45 | if (i2c_transfer(priv->i2c, msg, 2) != 2) { | ||
46 | err("I2C read reg failed, reg: %02x", reg); | ||
47 | return -EREMOTEIO; | ||
48 | } | ||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | static int fc0012_release(struct dvb_frontend *fe) | ||
53 | { | ||
54 | kfree(fe->tuner_priv); | ||
55 | fe->tuner_priv = NULL; | ||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | static int fc0012_init(struct dvb_frontend *fe) | ||
60 | { | ||
61 | struct fc0012_priv *priv = fe->tuner_priv; | ||
62 | int i, ret = 0; | ||
63 | unsigned char reg[] = { | ||
64 | 0x00, /* dummy reg. 0 */ | ||
65 | 0x05, /* reg. 0x01 */ | ||
66 | 0x10, /* reg. 0x02 */ | ||
67 | 0x00, /* reg. 0x03 */ | ||
68 | 0x00, /* reg. 0x04 */ | ||
69 | 0x0f, /* reg. 0x05: may also be 0x0a */ | ||
70 | 0x00, /* reg. 0x06: divider 2, VCO slow */ | ||
71 | 0x00, /* reg. 0x07: may also be 0x0f */ | ||
72 | 0xff, /* reg. 0x08: AGC Clock divide by 256, AGC gain 1/256, | ||
73 | Loop Bw 1/8 */ | ||
74 | 0x6e, /* reg. 0x09: Disable LoopThrough, Enable LoopThrough: 0x6f */ | ||
75 | 0xb8, /* reg. 0x0a: Disable LO Test Buffer */ | ||
76 | 0x82, /* reg. 0x0b: Output Clock is same as clock frequency, | ||
77 | may also be 0x83 */ | ||
78 | 0xfc, /* reg. 0x0c: depending on AGC Up-Down mode, may need 0xf8 */ | ||
79 | 0x02, /* reg. 0x0d: AGC Not Forcing & LNA Forcing, 0x02 for DVB-T */ | ||
80 | 0x00, /* reg. 0x0e */ | ||
81 | 0x00, /* reg. 0x0f */ | ||
82 | 0x00, /* reg. 0x10: may also be 0x0d */ | ||
83 | 0x00, /* reg. 0x11 */ | ||
84 | 0x1f, /* reg. 0x12: Set to maximum gain */ | ||
85 | 0x08, /* reg. 0x13: Set to Middle Gain: 0x08, | ||
86 | Low Gain: 0x00, High Gain: 0x10, enable IX2: 0x80 */ | ||
87 | 0x00, /* reg. 0x14 */ | ||
88 | 0x04, /* reg. 0x15: Enable LNA COMPS */ | ||
89 | }; | ||
90 | |||
91 | switch (priv->xtal_freq) { | ||
92 | case FC_XTAL_27_MHZ: | ||
93 | case FC_XTAL_28_8_MHZ: | ||
94 | reg[0x07] |= 0x20; | ||
95 | break; | ||
96 | case FC_XTAL_36_MHZ: | ||
97 | default: | ||
98 | break; | ||
99 | } | ||
100 | |||
101 | if (priv->dual_master) | ||
102 | reg[0x0c] |= 0x02; | ||
103 | |||
104 | if (fe->ops.i2c_gate_ctrl) | ||
105 | fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ | ||
106 | |||
107 | for (i = 1; i < sizeof(reg); i++) { | ||
108 | ret = fc0012_writereg(priv, i, reg[i]); | ||
109 | if (ret) | ||
110 | break; | ||
111 | } | ||
112 | |||
113 | if (fe->ops.i2c_gate_ctrl) | ||
114 | fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ | ||
115 | |||
116 | if (ret) | ||
117 | err("fc0012_writereg failed: %d", ret); | ||
118 | |||
119 | return ret; | ||
120 | } | ||
121 | |||
122 | static int fc0012_sleep(struct dvb_frontend *fe) | ||
123 | { | ||
124 | /* nothing to do here */ | ||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | static int fc0012_set_params(struct dvb_frontend *fe) | ||
129 | { | ||
130 | struct fc0012_priv *priv = fe->tuner_priv; | ||
131 | int i, ret = 0; | ||
132 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; | ||
133 | u32 freq = p->frequency / 1000; | ||
134 | u32 delsys = p->delivery_system; | ||
135 | unsigned char reg[7], am, pm, multi, tmp; | ||
136 | unsigned long f_vco; | ||
137 | unsigned short xtal_freq_khz_2, xin, xdiv; | ||
138 | int vco_select = false; | ||
139 | |||
140 | if (fe->callback) { | ||
141 | ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, | ||
142 | FC_FE_CALLBACK_VHF_ENABLE, (freq > 300000 ? 0 : 1)); | ||
143 | if (ret) | ||
144 | goto exit; | ||
145 | } | ||
146 | |||
147 | switch (priv->xtal_freq) { | ||
148 | case FC_XTAL_27_MHZ: | ||
149 | xtal_freq_khz_2 = 27000 / 2; | ||
150 | break; | ||
151 | case FC_XTAL_36_MHZ: | ||
152 | xtal_freq_khz_2 = 36000 / 2; | ||
153 | break; | ||
154 | case FC_XTAL_28_8_MHZ: | ||
155 | default: | ||
156 | xtal_freq_khz_2 = 28800 / 2; | ||
157 | break; | ||
158 | } | ||
159 | |||
160 | /* select frequency divider and the frequency of VCO */ | ||
161 | if (freq < 37084) { /* freq * 96 < 3560000 */ | ||
162 | multi = 96; | ||
163 | reg[5] = 0x82; | ||
164 | reg[6] = 0x00; | ||
165 | } else if (freq < 55625) { /* freq * 64 < 3560000 */ | ||
166 | multi = 64; | ||
167 | reg[5] = 0x82; | ||
168 | reg[6] = 0x02; | ||
169 | } else if (freq < 74167) { /* freq * 48 < 3560000 */ | ||
170 | multi = 48; | ||
171 | reg[5] = 0x42; | ||
172 | reg[6] = 0x00; | ||
173 | } else if (freq < 111250) { /* freq * 32 < 3560000 */ | ||
174 | multi = 32; | ||
175 | reg[5] = 0x42; | ||
176 | reg[6] = 0x02; | ||
177 | } else if (freq < 148334) { /* freq * 24 < 3560000 */ | ||
178 | multi = 24; | ||
179 | reg[5] = 0x22; | ||
180 | reg[6] = 0x00; | ||
181 | } else if (freq < 222500) { /* freq * 16 < 3560000 */ | ||
182 | multi = 16; | ||
183 | reg[5] = 0x22; | ||
184 | reg[6] = 0x02; | ||
185 | } else if (freq < 296667) { /* freq * 12 < 3560000 */ | ||
186 | multi = 12; | ||
187 | reg[5] = 0x12; | ||
188 | reg[6] = 0x00; | ||
189 | } else if (freq < 445000) { /* freq * 8 < 3560000 */ | ||
190 | multi = 8; | ||
191 | reg[5] = 0x12; | ||
192 | reg[6] = 0x02; | ||
193 | } else if (freq < 593334) { /* freq * 6 < 3560000 */ | ||
194 | multi = 6; | ||
195 | reg[5] = 0x0a; | ||
196 | reg[6] = 0x00; | ||
197 | } else { | ||
198 | multi = 4; | ||
199 | reg[5] = 0x0a; | ||
200 | reg[6] = 0x02; | ||
201 | } | ||
202 | |||
203 | f_vco = freq * multi; | ||
204 | |||
205 | if (f_vco >= 3060000) { | ||
206 | reg[6] |= 0x08; | ||
207 | vco_select = true; | ||
208 | } | ||
209 | |||
210 | if (freq >= 45000) { | ||
211 | /* From divided value (XDIV) determined the FA and FP value */ | ||
212 | xdiv = (unsigned short)(f_vco / xtal_freq_khz_2); | ||
213 | if ((f_vco - xdiv * xtal_freq_khz_2) >= (xtal_freq_khz_2 / 2)) | ||
214 | xdiv++; | ||
215 | |||
216 | pm = (unsigned char)(xdiv / 8); | ||
217 | am = (unsigned char)(xdiv - (8 * pm)); | ||
218 | |||
219 | if (am < 2) { | ||
220 | reg[1] = am + 8; | ||
221 | reg[2] = pm - 1; | ||
222 | } else { | ||
223 | reg[1] = am; | ||
224 | reg[2] = pm; | ||
225 | } | ||
226 | } else { | ||
227 | /* fix for frequency less than 45 MHz */ | ||
228 | reg[1] = 0x06; | ||
229 | reg[2] = 0x11; | ||
230 | } | ||
231 | |||
232 | /* fix clock out */ | ||
233 | reg[6] |= 0x20; | ||
234 | |||
235 | /* From VCO frequency determines the XIN ( fractional part of Delta | ||
236 | Sigma PLL) and divided value (XDIV) */ | ||
237 | xin = (unsigned short)(f_vco - (f_vco / xtal_freq_khz_2) * xtal_freq_khz_2); | ||
238 | xin = (xin << 15) / xtal_freq_khz_2; | ||
239 | if (xin >= 16384) | ||
240 | xin += 32768; | ||
241 | |||
242 | reg[3] = xin >> 8; /* xin with 9 bit resolution */ | ||
243 | reg[4] = xin & 0xff; | ||
244 | |||
245 | if (delsys == SYS_DVBT) { | ||
246 | reg[6] &= 0x3f; /* bits 6 and 7 describe the bandwidth */ | ||
247 | switch (p->bandwidth_hz) { | ||
248 | case 6000000: | ||
249 | reg[6] |= 0x80; | ||
250 | break; | ||
251 | case 7000000: | ||
252 | reg[6] |= 0x40; | ||
253 | break; | ||
254 | case 8000000: | ||
255 | default: | ||
256 | break; | ||
257 | } | ||
258 | } else { | ||
259 | err("%s: modulation type not supported!", __func__); | ||
260 | return -EINVAL; | ||
261 | } | ||
262 | |||
263 | /* modified for Realtek demod */ | ||
264 | reg[5] |= 0x07; | ||
265 | |||
266 | if (fe->ops.i2c_gate_ctrl) | ||
267 | fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ | ||
268 | |||
269 | for (i = 1; i <= 6; i++) { | ||
270 | ret = fc0012_writereg(priv, i, reg[i]); | ||
271 | if (ret) | ||
272 | goto exit; | ||
273 | } | ||
274 | |||
275 | /* VCO Calibration */ | ||
276 | ret = fc0012_writereg(priv, 0x0e, 0x80); | ||
277 | if (!ret) | ||
278 | ret = fc0012_writereg(priv, 0x0e, 0x00); | ||
279 | |||
280 | /* VCO Re-Calibration if needed */ | ||
281 | if (!ret) | ||
282 | ret = fc0012_writereg(priv, 0x0e, 0x00); | ||
283 | |||
284 | if (!ret) { | ||
285 | msleep(10); | ||
286 | ret = fc0012_readreg(priv, 0x0e, &tmp); | ||
287 | } | ||
288 | if (ret) | ||
289 | goto exit; | ||
290 | |||
291 | /* vco selection */ | ||
292 | tmp &= 0x3f; | ||
293 | |||
294 | if (vco_select) { | ||
295 | if (tmp > 0x3c) { | ||
296 | reg[6] &= ~0x08; | ||
297 | ret = fc0012_writereg(priv, 0x06, reg[6]); | ||
298 | if (!ret) | ||
299 | ret = fc0012_writereg(priv, 0x0e, 0x80); | ||
300 | if (!ret) | ||
301 | ret = fc0012_writereg(priv, 0x0e, 0x00); | ||
302 | } | ||
303 | } else { | ||
304 | if (tmp < 0x02) { | ||
305 | reg[6] |= 0x08; | ||
306 | ret = fc0012_writereg(priv, 0x06, reg[6]); | ||
307 | if (!ret) | ||
308 | ret = fc0012_writereg(priv, 0x0e, 0x80); | ||
309 | if (!ret) | ||
310 | ret = fc0012_writereg(priv, 0x0e, 0x00); | ||
311 | } | ||
312 | } | ||
313 | |||
314 | priv->frequency = p->frequency; | ||
315 | priv->bandwidth = p->bandwidth_hz; | ||
316 | |||
317 | exit: | ||
318 | if (fe->ops.i2c_gate_ctrl) | ||
319 | fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ | ||
320 | if (ret) | ||
321 | warn("%s: failed: %d", __func__, ret); | ||
322 | return ret; | ||
323 | } | ||
324 | |||
325 | static int fc0012_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
326 | { | ||
327 | struct fc0012_priv *priv = fe->tuner_priv; | ||
328 | *frequency = priv->frequency; | ||
329 | return 0; | ||
330 | } | ||
331 | |||
332 | static int fc0012_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
333 | { | ||
334 | /* CHECK: always ? */ | ||
335 | *frequency = 0; | ||
336 | return 0; | ||
337 | } | ||
338 | |||
339 | static int fc0012_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) | ||
340 | { | ||
341 | struct fc0012_priv *priv = fe->tuner_priv; | ||
342 | *bandwidth = priv->bandwidth; | ||
343 | return 0; | ||
344 | } | ||
345 | |||
346 | #define INPUT_ADC_LEVEL -8 | ||
347 | |||
348 | static int fc0012_get_rf_strength(struct dvb_frontend *fe, u16 *strength) | ||
349 | { | ||
350 | struct fc0012_priv *priv = fe->tuner_priv; | ||
351 | int ret; | ||
352 | unsigned char tmp; | ||
353 | int int_temp, lna_gain, int_lna, tot_agc_gain, power; | ||
354 | const int fc0012_lna_gain_table[] = { | ||
355 | /* low gain */ | ||
356 | -63, -58, -99, -73, | ||
357 | -63, -65, -54, -60, | ||
358 | /* middle gain */ | ||
359 | 71, 70, 68, 67, | ||
360 | 65, 63, 61, 58, | ||
361 | /* high gain */ | ||
362 | 197, 191, 188, 186, | ||
363 | 184, 182, 181, 179, | ||
364 | }; | ||
365 | |||
366 | if (fe->ops.i2c_gate_ctrl) | ||
367 | fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ | ||
368 | |||
369 | ret = fc0012_writereg(priv, 0x12, 0x00); | ||
370 | if (ret) | ||
371 | goto err; | ||
372 | |||
373 | ret = fc0012_readreg(priv, 0x12, &tmp); | ||
374 | if (ret) | ||
375 | goto err; | ||
376 | int_temp = tmp; | ||
377 | |||
378 | ret = fc0012_readreg(priv, 0x13, &tmp); | ||
379 | if (ret) | ||
380 | goto err; | ||
381 | lna_gain = tmp & 0x1f; | ||
382 | |||
383 | if (fe->ops.i2c_gate_ctrl) | ||
384 | fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ | ||
385 | |||
386 | if (lna_gain < ARRAY_SIZE(fc0012_lna_gain_table)) { | ||
387 | int_lna = fc0012_lna_gain_table[lna_gain]; | ||
388 | tot_agc_gain = (abs((int_temp >> 5) - 7) - 2 + | ||
389 | (int_temp & 0x1f)) * 2; | ||
390 | power = INPUT_ADC_LEVEL - tot_agc_gain - int_lna / 10; | ||
391 | |||
392 | if (power >= 45) | ||
393 | *strength = 255; /* 100% */ | ||
394 | else if (power < -95) | ||
395 | *strength = 0; | ||
396 | else | ||
397 | *strength = (power + 95) * 255 / 140; | ||
398 | |||
399 | *strength |= *strength << 8; | ||
400 | } else { | ||
401 | ret = -1; | ||
402 | } | ||
403 | |||
404 | goto exit; | ||
405 | |||
406 | err: | ||
407 | if (fe->ops.i2c_gate_ctrl) | ||
408 | fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ | ||
409 | exit: | ||
410 | if (ret) | ||
411 | warn("%s: failed: %d", __func__, ret); | ||
412 | return ret; | ||
413 | } | ||
414 | |||
415 | static const struct dvb_tuner_ops fc0012_tuner_ops = { | ||
416 | .info = { | ||
417 | .name = "Fitipower FC0012", | ||
418 | |||
419 | .frequency_min = 37000000, /* estimate */ | ||
420 | .frequency_max = 862000000, /* estimate */ | ||
421 | .frequency_step = 0, | ||
422 | }, | ||
423 | |||
424 | .release = fc0012_release, | ||
425 | |||
426 | .init = fc0012_init, | ||
427 | .sleep = fc0012_sleep, | ||
428 | |||
429 | .set_params = fc0012_set_params, | ||
430 | |||
431 | .get_frequency = fc0012_get_frequency, | ||
432 | .get_if_frequency = fc0012_get_if_frequency, | ||
433 | .get_bandwidth = fc0012_get_bandwidth, | ||
434 | |||
435 | .get_rf_strength = fc0012_get_rf_strength, | ||
436 | }; | ||
437 | |||
438 | struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe, | ||
439 | struct i2c_adapter *i2c, u8 i2c_address, int dual_master, | ||
440 | enum fc001x_xtal_freq xtal_freq) | ||
441 | { | ||
442 | struct fc0012_priv *priv = NULL; | ||
443 | |||
444 | priv = kzalloc(sizeof(struct fc0012_priv), GFP_KERNEL); | ||
445 | if (priv == NULL) | ||
446 | return NULL; | ||
447 | |||
448 | priv->i2c = i2c; | ||
449 | priv->dual_master = dual_master; | ||
450 | priv->addr = i2c_address; | ||
451 | priv->xtal_freq = xtal_freq; | ||
452 | |||
453 | info("Fitipower FC0012 successfully attached."); | ||
454 | |||
455 | fe->tuner_priv = priv; | ||
456 | |||
457 | memcpy(&fe->ops.tuner_ops, &fc0012_tuner_ops, | ||
458 | sizeof(struct dvb_tuner_ops)); | ||
459 | |||
460 | return fe; | ||
461 | } | ||
462 | EXPORT_SYMBOL(fc0012_attach); | ||
463 | |||
464 | MODULE_DESCRIPTION("Fitipower FC0012 silicon tuner driver"); | ||
465 | MODULE_AUTHOR("Hans-Frieder Vogt <hfvogt@gmx.net>"); | ||
466 | MODULE_LICENSE("GPL"); | ||
467 | MODULE_VERSION("0.6"); | ||
diff --git a/drivers/media/tuners/fc0012.h b/drivers/media/tuners/fc0012.h new file mode 100644 index 000000000000..4dbd5efe8845 --- /dev/null +++ b/drivers/media/tuners/fc0012.h | |||
@@ -0,0 +1,44 @@ | |||
1 | /* | ||
2 | * Fitipower FC0012 tuner driver - include | ||
3 | * | ||
4 | * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net> | ||
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 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef _FC0012_H_ | ||
22 | #define _FC0012_H_ | ||
23 | |||
24 | #include "dvb_frontend.h" | ||
25 | #include "fc001x-common.h" | ||
26 | |||
27 | #if defined(CONFIG_MEDIA_TUNER_FC0012) || \ | ||
28 | (defined(CONFIG_MEDIA_TUNER_FC0012_MODULE) && defined(MODULE)) | ||
29 | extern struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe, | ||
30 | struct i2c_adapter *i2c, | ||
31 | u8 i2c_address, int dual_master, | ||
32 | enum fc001x_xtal_freq xtal_freq); | ||
33 | #else | ||
34 | static inline struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe, | ||
35 | struct i2c_adapter *i2c, | ||
36 | u8 i2c_address, int dual_master, | ||
37 | enum fc001x_xtal_freq xtal_freq) | ||
38 | { | ||
39 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
40 | return NULL; | ||
41 | } | ||
42 | #endif | ||
43 | |||
44 | #endif | ||
diff --git a/drivers/media/tuners/fc0013-priv.h b/drivers/media/tuners/fc0013-priv.h new file mode 100644 index 000000000000..bfd49dedea22 --- /dev/null +++ b/drivers/media/tuners/fc0013-priv.h | |||
@@ -0,0 +1,44 @@ | |||
1 | /* | ||
2 | * Fitipower FC0013 tuner driver | ||
3 | * | ||
4 | * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net> | ||
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 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef _FC0013_PRIV_H_ | ||
23 | #define _FC0013_PRIV_H_ | ||
24 | |||
25 | #define LOG_PREFIX "fc0013" | ||
26 | |||
27 | #undef err | ||
28 | #define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) | ||
29 | #undef info | ||
30 | #define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) | ||
31 | #undef warn | ||
32 | #define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) | ||
33 | |||
34 | struct fc0013_priv { | ||
35 | struct i2c_adapter *i2c; | ||
36 | u8 addr; | ||
37 | u8 dual_master; | ||
38 | u8 xtal_freq; | ||
39 | |||
40 | u32 frequency; | ||
41 | u32 bandwidth; | ||
42 | }; | ||
43 | |||
44 | #endif | ||
diff --git a/drivers/media/tuners/fc0013.c b/drivers/media/tuners/fc0013.c new file mode 100644 index 000000000000..bd8f0f1e8f3b --- /dev/null +++ b/drivers/media/tuners/fc0013.c | |||
@@ -0,0 +1,634 @@ | |||
1 | /* | ||
2 | * Fitipower FC0013 tuner driver | ||
3 | * | ||
4 | * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net> | ||
5 | * partially based on driver code from Fitipower | ||
6 | * Copyright (C) 2010 Fitipower Integrated Technology Inc | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include "fc0013.h" | ||
25 | #include "fc0013-priv.h" | ||
26 | |||
27 | static int fc0013_writereg(struct fc0013_priv *priv, u8 reg, u8 val) | ||
28 | { | ||
29 | u8 buf[2] = {reg, val}; | ||
30 | struct i2c_msg msg = { | ||
31 | .addr = priv->addr, .flags = 0, .buf = buf, .len = 2 | ||
32 | }; | ||
33 | |||
34 | if (i2c_transfer(priv->i2c, &msg, 1) != 1) { | ||
35 | err("I2C write reg failed, reg: %02x, val: %02x", reg, val); | ||
36 | return -EREMOTEIO; | ||
37 | } | ||
38 | return 0; | ||
39 | } | ||
40 | |||
41 | static int fc0013_readreg(struct fc0013_priv *priv, u8 reg, u8 *val) | ||
42 | { | ||
43 | struct i2c_msg msg[2] = { | ||
44 | { .addr = priv->addr, .flags = 0, .buf = ®, .len = 1 }, | ||
45 | { .addr = priv->addr, .flags = I2C_M_RD, .buf = val, .len = 1 }, | ||
46 | }; | ||
47 | |||
48 | if (i2c_transfer(priv->i2c, msg, 2) != 2) { | ||
49 | err("I2C read reg failed, reg: %02x", reg); | ||
50 | return -EREMOTEIO; | ||
51 | } | ||
52 | return 0; | ||
53 | } | ||
54 | |||
55 | static int fc0013_release(struct dvb_frontend *fe) | ||
56 | { | ||
57 | kfree(fe->tuner_priv); | ||
58 | fe->tuner_priv = NULL; | ||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | static int fc0013_init(struct dvb_frontend *fe) | ||
63 | { | ||
64 | struct fc0013_priv *priv = fe->tuner_priv; | ||
65 | int i, ret = 0; | ||
66 | unsigned char reg[] = { | ||
67 | 0x00, /* reg. 0x00: dummy */ | ||
68 | 0x09, /* reg. 0x01 */ | ||
69 | 0x16, /* reg. 0x02 */ | ||
70 | 0x00, /* reg. 0x03 */ | ||
71 | 0x00, /* reg. 0x04 */ | ||
72 | 0x17, /* reg. 0x05 */ | ||
73 | 0x02, /* reg. 0x06 */ | ||
74 | 0x0a, /* reg. 0x07: CHECK */ | ||
75 | 0xff, /* reg. 0x08: AGC Clock divide by 256, AGC gain 1/256, | ||
76 | Loop Bw 1/8 */ | ||
77 | 0x6f, /* reg. 0x09: enable LoopThrough */ | ||
78 | 0xb8, /* reg. 0x0a: Disable LO Test Buffer */ | ||
79 | 0x82, /* reg. 0x0b: CHECK */ | ||
80 | 0xfc, /* reg. 0x0c: depending on AGC Up-Down mode, may need 0xf8 */ | ||
81 | 0x01, /* reg. 0x0d: AGC Not Forcing & LNA Forcing, may need 0x02 */ | ||
82 | 0x00, /* reg. 0x0e */ | ||
83 | 0x00, /* reg. 0x0f */ | ||
84 | 0x00, /* reg. 0x10 */ | ||
85 | 0x00, /* reg. 0x11 */ | ||
86 | 0x00, /* reg. 0x12 */ | ||
87 | 0x00, /* reg. 0x13 */ | ||
88 | 0x50, /* reg. 0x14: DVB-t High Gain, UHF. | ||
89 | Middle Gain: 0x48, Low Gain: 0x40 */ | ||
90 | 0x01, /* reg. 0x15 */ | ||
91 | }; | ||
92 | |||
93 | switch (priv->xtal_freq) { | ||
94 | case FC_XTAL_27_MHZ: | ||
95 | case FC_XTAL_28_8_MHZ: | ||
96 | reg[0x07] |= 0x20; | ||
97 | break; | ||
98 | case FC_XTAL_36_MHZ: | ||
99 | default: | ||
100 | break; | ||
101 | } | ||
102 | |||
103 | if (priv->dual_master) | ||
104 | reg[0x0c] |= 0x02; | ||
105 | |||
106 | if (fe->ops.i2c_gate_ctrl) | ||
107 | fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ | ||
108 | |||
109 | for (i = 1; i < sizeof(reg); i++) { | ||
110 | ret = fc0013_writereg(priv, i, reg[i]); | ||
111 | if (ret) | ||
112 | break; | ||
113 | } | ||
114 | |||
115 | if (fe->ops.i2c_gate_ctrl) | ||
116 | fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ | ||
117 | |||
118 | if (ret) | ||
119 | err("fc0013_writereg failed: %d", ret); | ||
120 | |||
121 | return ret; | ||
122 | } | ||
123 | |||
124 | static int fc0013_sleep(struct dvb_frontend *fe) | ||
125 | { | ||
126 | /* nothing to do here */ | ||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | int fc0013_rc_cal_add(struct dvb_frontend *fe, int rc_val) | ||
131 | { | ||
132 | struct fc0013_priv *priv = fe->tuner_priv; | ||
133 | int ret; | ||
134 | u8 rc_cal; | ||
135 | int val; | ||
136 | |||
137 | if (fe->ops.i2c_gate_ctrl) | ||
138 | fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ | ||
139 | |||
140 | /* push rc_cal value, get rc_cal value */ | ||
141 | ret = fc0013_writereg(priv, 0x10, 0x00); | ||
142 | if (ret) | ||
143 | goto error_out; | ||
144 | |||
145 | /* get rc_cal value */ | ||
146 | ret = fc0013_readreg(priv, 0x10, &rc_cal); | ||
147 | if (ret) | ||
148 | goto error_out; | ||
149 | |||
150 | rc_cal &= 0x0f; | ||
151 | |||
152 | val = (int)rc_cal + rc_val; | ||
153 | |||
154 | /* forcing rc_cal */ | ||
155 | ret = fc0013_writereg(priv, 0x0d, 0x11); | ||
156 | if (ret) | ||
157 | goto error_out; | ||
158 | |||
159 | /* modify rc_cal value */ | ||
160 | if (val > 15) | ||
161 | ret = fc0013_writereg(priv, 0x10, 0x0f); | ||
162 | else if (val < 0) | ||
163 | ret = fc0013_writereg(priv, 0x10, 0x00); | ||
164 | else | ||
165 | ret = fc0013_writereg(priv, 0x10, (u8)val); | ||
166 | |||
167 | error_out: | ||
168 | if (fe->ops.i2c_gate_ctrl) | ||
169 | fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ | ||
170 | |||
171 | return ret; | ||
172 | } | ||
173 | EXPORT_SYMBOL(fc0013_rc_cal_add); | ||
174 | |||
175 | int fc0013_rc_cal_reset(struct dvb_frontend *fe) | ||
176 | { | ||
177 | struct fc0013_priv *priv = fe->tuner_priv; | ||
178 | int ret; | ||
179 | |||
180 | if (fe->ops.i2c_gate_ctrl) | ||
181 | fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ | ||
182 | |||
183 | ret = fc0013_writereg(priv, 0x0d, 0x01); | ||
184 | if (!ret) | ||
185 | ret = fc0013_writereg(priv, 0x10, 0x00); | ||
186 | |||
187 | if (fe->ops.i2c_gate_ctrl) | ||
188 | fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ | ||
189 | |||
190 | return ret; | ||
191 | } | ||
192 | EXPORT_SYMBOL(fc0013_rc_cal_reset); | ||
193 | |||
194 | static int fc0013_set_vhf_track(struct fc0013_priv *priv, u32 freq) | ||
195 | { | ||
196 | int ret; | ||
197 | u8 tmp; | ||
198 | |||
199 | ret = fc0013_readreg(priv, 0x1d, &tmp); | ||
200 | if (ret) | ||
201 | goto error_out; | ||
202 | tmp &= 0xe3; | ||
203 | if (freq <= 177500) { /* VHF Track: 7 */ | ||
204 | ret = fc0013_writereg(priv, 0x1d, tmp | 0x1c); | ||
205 | } else if (freq <= 184500) { /* VHF Track: 6 */ | ||
206 | ret = fc0013_writereg(priv, 0x1d, tmp | 0x18); | ||
207 | } else if (freq <= 191500) { /* VHF Track: 5 */ | ||
208 | ret = fc0013_writereg(priv, 0x1d, tmp | 0x14); | ||
209 | } else if (freq <= 198500) { /* VHF Track: 4 */ | ||
210 | ret = fc0013_writereg(priv, 0x1d, tmp | 0x10); | ||
211 | } else if (freq <= 205500) { /* VHF Track: 3 */ | ||
212 | ret = fc0013_writereg(priv, 0x1d, tmp | 0x0c); | ||
213 | } else if (freq <= 219500) { /* VHF Track: 2 */ | ||
214 | ret = fc0013_writereg(priv, 0x1d, tmp | 0x08); | ||
215 | } else if (freq < 300000) { /* VHF Track: 1 */ | ||
216 | ret = fc0013_writereg(priv, 0x1d, tmp | 0x04); | ||
217 | } else { /* UHF and GPS */ | ||
218 | ret = fc0013_writereg(priv, 0x1d, tmp | 0x1c); | ||
219 | } | ||
220 | if (ret) | ||
221 | goto error_out; | ||
222 | error_out: | ||
223 | return ret; | ||
224 | } | ||
225 | |||
226 | static int fc0013_set_params(struct dvb_frontend *fe) | ||
227 | { | ||
228 | struct fc0013_priv *priv = fe->tuner_priv; | ||
229 | int i, ret = 0; | ||
230 | struct dtv_frontend_properties *p = &fe->dtv_property_cache; | ||
231 | u32 freq = p->frequency / 1000; | ||
232 | u32 delsys = p->delivery_system; | ||
233 | unsigned char reg[7], am, pm, multi, tmp; | ||
234 | unsigned long f_vco; | ||
235 | unsigned short xtal_freq_khz_2, xin, xdiv; | ||
236 | int vco_select = false; | ||
237 | |||
238 | if (fe->callback) { | ||
239 | ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, | ||
240 | FC_FE_CALLBACK_VHF_ENABLE, (freq > 300000 ? 0 : 1)); | ||
241 | if (ret) | ||
242 | goto exit; | ||
243 | } | ||
244 | |||
245 | switch (priv->xtal_freq) { | ||
246 | case FC_XTAL_27_MHZ: | ||
247 | xtal_freq_khz_2 = 27000 / 2; | ||
248 | break; | ||
249 | case FC_XTAL_36_MHZ: | ||
250 | xtal_freq_khz_2 = 36000 / 2; | ||
251 | break; | ||
252 | case FC_XTAL_28_8_MHZ: | ||
253 | default: | ||
254 | xtal_freq_khz_2 = 28800 / 2; | ||
255 | break; | ||
256 | } | ||
257 | |||
258 | if (fe->ops.i2c_gate_ctrl) | ||
259 | fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ | ||
260 | |||
261 | /* set VHF track */ | ||
262 | ret = fc0013_set_vhf_track(priv, freq); | ||
263 | if (ret) | ||
264 | goto exit; | ||
265 | |||
266 | if (freq < 300000) { | ||
267 | /* enable VHF filter */ | ||
268 | ret = fc0013_readreg(priv, 0x07, &tmp); | ||
269 | if (ret) | ||
270 | goto exit; | ||
271 | ret = fc0013_writereg(priv, 0x07, tmp | 0x10); | ||
272 | if (ret) | ||
273 | goto exit; | ||
274 | |||
275 | /* disable UHF & disable GPS */ | ||
276 | ret = fc0013_readreg(priv, 0x14, &tmp); | ||
277 | if (ret) | ||
278 | goto exit; | ||
279 | ret = fc0013_writereg(priv, 0x14, tmp & 0x1f); | ||
280 | if (ret) | ||
281 | goto exit; | ||
282 | } else if (freq <= 862000) { | ||
283 | /* disable VHF filter */ | ||
284 | ret = fc0013_readreg(priv, 0x07, &tmp); | ||
285 | if (ret) | ||
286 | goto exit; | ||
287 | ret = fc0013_writereg(priv, 0x07, tmp & 0xef); | ||
288 | if (ret) | ||
289 | goto exit; | ||
290 | |||
291 | /* enable UHF & disable GPS */ | ||
292 | ret = fc0013_readreg(priv, 0x14, &tmp); | ||
293 | if (ret) | ||
294 | goto exit; | ||
295 | ret = fc0013_writereg(priv, 0x14, (tmp & 0x1f) | 0x40); | ||
296 | if (ret) | ||
297 | goto exit; | ||
298 | } else { | ||
299 | /* disable VHF filter */ | ||
300 | ret = fc0013_readreg(priv, 0x07, &tmp); | ||
301 | if (ret) | ||
302 | goto exit; | ||
303 | ret = fc0013_writereg(priv, 0x07, tmp & 0xef); | ||
304 | if (ret) | ||
305 | goto exit; | ||
306 | |||
307 | /* disable UHF & enable GPS */ | ||
308 | ret = fc0013_readreg(priv, 0x14, &tmp); | ||
309 | if (ret) | ||
310 | goto exit; | ||
311 | ret = fc0013_writereg(priv, 0x14, (tmp & 0x1f) | 0x20); | ||
312 | if (ret) | ||
313 | goto exit; | ||
314 | } | ||
315 | |||
316 | /* select frequency divider and the frequency of VCO */ | ||
317 | if (freq < 37084) { /* freq * 96 < 3560000 */ | ||
318 | multi = 96; | ||
319 | reg[5] = 0x82; | ||
320 | reg[6] = 0x00; | ||
321 | } else if (freq < 55625) { /* freq * 64 < 3560000 */ | ||
322 | multi = 64; | ||
323 | reg[5] = 0x02; | ||
324 | reg[6] = 0x02; | ||
325 | } else if (freq < 74167) { /* freq * 48 < 3560000 */ | ||
326 | multi = 48; | ||
327 | reg[5] = 0x42; | ||
328 | reg[6] = 0x00; | ||
329 | } else if (freq < 111250) { /* freq * 32 < 3560000 */ | ||
330 | multi = 32; | ||
331 | reg[5] = 0x82; | ||
332 | reg[6] = 0x02; | ||
333 | } else if (freq < 148334) { /* freq * 24 < 3560000 */ | ||
334 | multi = 24; | ||
335 | reg[5] = 0x22; | ||
336 | reg[6] = 0x00; | ||
337 | } else if (freq < 222500) { /* freq * 16 < 3560000 */ | ||
338 | multi = 16; | ||
339 | reg[5] = 0x42; | ||
340 | reg[6] = 0x02; | ||
341 | } else if (freq < 296667) { /* freq * 12 < 3560000 */ | ||
342 | multi = 12; | ||
343 | reg[5] = 0x12; | ||
344 | reg[6] = 0x00; | ||
345 | } else if (freq < 445000) { /* freq * 8 < 3560000 */ | ||
346 | multi = 8; | ||
347 | reg[5] = 0x22; | ||
348 | reg[6] = 0x02; | ||
349 | } else if (freq < 593334) { /* freq * 6 < 3560000 */ | ||
350 | multi = 6; | ||
351 | reg[5] = 0x0a; | ||
352 | reg[6] = 0x00; | ||
353 | } else if (freq < 950000) { /* freq * 4 < 3800000 */ | ||
354 | multi = 4; | ||
355 | reg[5] = 0x12; | ||
356 | reg[6] = 0x02; | ||
357 | } else { | ||
358 | multi = 2; | ||
359 | reg[5] = 0x0a; | ||
360 | reg[6] = 0x02; | ||
361 | } | ||
362 | |||
363 | f_vco = freq * multi; | ||
364 | |||
365 | if (f_vco >= 3060000) { | ||
366 | reg[6] |= 0x08; | ||
367 | vco_select = true; | ||
368 | } | ||
369 | |||
370 | if (freq >= 45000) { | ||
371 | /* From divided value (XDIV) determined the FA and FP value */ | ||
372 | xdiv = (unsigned short)(f_vco / xtal_freq_khz_2); | ||
373 | if ((f_vco - xdiv * xtal_freq_khz_2) >= (xtal_freq_khz_2 / 2)) | ||
374 | xdiv++; | ||
375 | |||
376 | pm = (unsigned char)(xdiv / 8); | ||
377 | am = (unsigned char)(xdiv - (8 * pm)); | ||
378 | |||
379 | if (am < 2) { | ||
380 | reg[1] = am + 8; | ||
381 | reg[2] = pm - 1; | ||
382 | } else { | ||
383 | reg[1] = am; | ||
384 | reg[2] = pm; | ||
385 | } | ||
386 | } else { | ||
387 | /* fix for frequency less than 45 MHz */ | ||
388 | reg[1] = 0x06; | ||
389 | reg[2] = 0x11; | ||
390 | } | ||
391 | |||
392 | /* fix clock out */ | ||
393 | reg[6] |= 0x20; | ||
394 | |||
395 | /* From VCO frequency determines the XIN ( fractional part of Delta | ||
396 | Sigma PLL) and divided value (XDIV) */ | ||
397 | xin = (unsigned short)(f_vco - (f_vco / xtal_freq_khz_2) * xtal_freq_khz_2); | ||
398 | xin = (xin << 15) / xtal_freq_khz_2; | ||
399 | if (xin >= 16384) | ||
400 | xin += 32768; | ||
401 | |||
402 | reg[3] = xin >> 8; | ||
403 | reg[4] = xin & 0xff; | ||
404 | |||
405 | if (delsys == SYS_DVBT) { | ||
406 | reg[6] &= 0x3f; /* bits 6 and 7 describe the bandwidth */ | ||
407 | switch (p->bandwidth_hz) { | ||
408 | case 6000000: | ||
409 | reg[6] |= 0x80; | ||
410 | break; | ||
411 | case 7000000: | ||
412 | reg[6] |= 0x40; | ||
413 | break; | ||
414 | case 8000000: | ||
415 | default: | ||
416 | break; | ||
417 | } | ||
418 | } else { | ||
419 | err("%s: modulation type not supported!", __func__); | ||
420 | return -EINVAL; | ||
421 | } | ||
422 | |||
423 | /* modified for Realtek demod */ | ||
424 | reg[5] |= 0x07; | ||
425 | |||
426 | for (i = 1; i <= 6; i++) { | ||
427 | ret = fc0013_writereg(priv, i, reg[i]); | ||
428 | if (ret) | ||
429 | goto exit; | ||
430 | } | ||
431 | |||
432 | ret = fc0013_readreg(priv, 0x11, &tmp); | ||
433 | if (ret) | ||
434 | goto exit; | ||
435 | if (multi == 64) | ||
436 | ret = fc0013_writereg(priv, 0x11, tmp | 0x04); | ||
437 | else | ||
438 | ret = fc0013_writereg(priv, 0x11, tmp & 0xfb); | ||
439 | if (ret) | ||
440 | goto exit; | ||
441 | |||
442 | /* VCO Calibration */ | ||
443 | ret = fc0013_writereg(priv, 0x0e, 0x80); | ||
444 | if (!ret) | ||
445 | ret = fc0013_writereg(priv, 0x0e, 0x00); | ||
446 | |||
447 | /* VCO Re-Calibration if needed */ | ||
448 | if (!ret) | ||
449 | ret = fc0013_writereg(priv, 0x0e, 0x00); | ||
450 | |||
451 | if (!ret) { | ||
452 | msleep(10); | ||
453 | ret = fc0013_readreg(priv, 0x0e, &tmp); | ||
454 | } | ||
455 | if (ret) | ||
456 | goto exit; | ||
457 | |||
458 | /* vco selection */ | ||
459 | tmp &= 0x3f; | ||
460 | |||
461 | if (vco_select) { | ||
462 | if (tmp > 0x3c) { | ||
463 | reg[6] &= ~0x08; | ||
464 | ret = fc0013_writereg(priv, 0x06, reg[6]); | ||
465 | if (!ret) | ||
466 | ret = fc0013_writereg(priv, 0x0e, 0x80); | ||
467 | if (!ret) | ||
468 | ret = fc0013_writereg(priv, 0x0e, 0x00); | ||
469 | } | ||
470 | } else { | ||
471 | if (tmp < 0x02) { | ||
472 | reg[6] |= 0x08; | ||
473 | ret = fc0013_writereg(priv, 0x06, reg[6]); | ||
474 | if (!ret) | ||
475 | ret = fc0013_writereg(priv, 0x0e, 0x80); | ||
476 | if (!ret) | ||
477 | ret = fc0013_writereg(priv, 0x0e, 0x00); | ||
478 | } | ||
479 | } | ||
480 | |||
481 | priv->frequency = p->frequency; | ||
482 | priv->bandwidth = p->bandwidth_hz; | ||
483 | |||
484 | exit: | ||
485 | if (fe->ops.i2c_gate_ctrl) | ||
486 | fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ | ||
487 | if (ret) | ||
488 | warn("%s: failed: %d", __func__, ret); | ||
489 | return ret; | ||
490 | } | ||
491 | |||
492 | static int fc0013_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
493 | { | ||
494 | struct fc0013_priv *priv = fe->tuner_priv; | ||
495 | *frequency = priv->frequency; | ||
496 | return 0; | ||
497 | } | ||
498 | |||
499 | static int fc0013_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
500 | { | ||
501 | /* always ? */ | ||
502 | *frequency = 0; | ||
503 | return 0; | ||
504 | } | ||
505 | |||
506 | static int fc0013_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) | ||
507 | { | ||
508 | struct fc0013_priv *priv = fe->tuner_priv; | ||
509 | *bandwidth = priv->bandwidth; | ||
510 | return 0; | ||
511 | } | ||
512 | |||
513 | #define INPUT_ADC_LEVEL -8 | ||
514 | |||
515 | static int fc0013_get_rf_strength(struct dvb_frontend *fe, u16 *strength) | ||
516 | { | ||
517 | struct fc0013_priv *priv = fe->tuner_priv; | ||
518 | int ret; | ||
519 | unsigned char tmp; | ||
520 | int int_temp, lna_gain, int_lna, tot_agc_gain, power; | ||
521 | const int fc0013_lna_gain_table[] = { | ||
522 | /* low gain */ | ||
523 | -63, -58, -99, -73, | ||
524 | -63, -65, -54, -60, | ||
525 | /* middle gain */ | ||
526 | 71, 70, 68, 67, | ||
527 | 65, 63, 61, 58, | ||
528 | /* high gain */ | ||
529 | 197, 191, 188, 186, | ||
530 | 184, 182, 181, 179, | ||
531 | }; | ||
532 | |||
533 | if (fe->ops.i2c_gate_ctrl) | ||
534 | fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ | ||
535 | |||
536 | ret = fc0013_writereg(priv, 0x13, 0x00); | ||
537 | if (ret) | ||
538 | goto err; | ||
539 | |||
540 | ret = fc0013_readreg(priv, 0x13, &tmp); | ||
541 | if (ret) | ||
542 | goto err; | ||
543 | int_temp = tmp; | ||
544 | |||
545 | ret = fc0013_readreg(priv, 0x14, &tmp); | ||
546 | if (ret) | ||
547 | goto err; | ||
548 | lna_gain = tmp & 0x1f; | ||
549 | |||
550 | if (fe->ops.i2c_gate_ctrl) | ||
551 | fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ | ||
552 | |||
553 | if (lna_gain < ARRAY_SIZE(fc0013_lna_gain_table)) { | ||
554 | int_lna = fc0013_lna_gain_table[lna_gain]; | ||
555 | tot_agc_gain = (abs((int_temp >> 5) - 7) - 2 + | ||
556 | (int_temp & 0x1f)) * 2; | ||
557 | power = INPUT_ADC_LEVEL - tot_agc_gain - int_lna / 10; | ||
558 | |||
559 | if (power >= 45) | ||
560 | *strength = 255; /* 100% */ | ||
561 | else if (power < -95) | ||
562 | *strength = 0; | ||
563 | else | ||
564 | *strength = (power + 95) * 255 / 140; | ||
565 | |||
566 | *strength |= *strength << 8; | ||
567 | } else { | ||
568 | ret = -1; | ||
569 | } | ||
570 | |||
571 | goto exit; | ||
572 | |||
573 | err: | ||
574 | if (fe->ops.i2c_gate_ctrl) | ||
575 | fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ | ||
576 | exit: | ||
577 | if (ret) | ||
578 | warn("%s: failed: %d", __func__, ret); | ||
579 | return ret; | ||
580 | } | ||
581 | |||
582 | static const struct dvb_tuner_ops fc0013_tuner_ops = { | ||
583 | .info = { | ||
584 | .name = "Fitipower FC0013", | ||
585 | |||
586 | .frequency_min = 37000000, /* estimate */ | ||
587 | .frequency_max = 1680000000, /* CHECK */ | ||
588 | .frequency_step = 0, | ||
589 | }, | ||
590 | |||
591 | .release = fc0013_release, | ||
592 | |||
593 | .init = fc0013_init, | ||
594 | .sleep = fc0013_sleep, | ||
595 | |||
596 | .set_params = fc0013_set_params, | ||
597 | |||
598 | .get_frequency = fc0013_get_frequency, | ||
599 | .get_if_frequency = fc0013_get_if_frequency, | ||
600 | .get_bandwidth = fc0013_get_bandwidth, | ||
601 | |||
602 | .get_rf_strength = fc0013_get_rf_strength, | ||
603 | }; | ||
604 | |||
605 | struct dvb_frontend *fc0013_attach(struct dvb_frontend *fe, | ||
606 | struct i2c_adapter *i2c, u8 i2c_address, int dual_master, | ||
607 | enum fc001x_xtal_freq xtal_freq) | ||
608 | { | ||
609 | struct fc0013_priv *priv = NULL; | ||
610 | |||
611 | priv = kzalloc(sizeof(struct fc0013_priv), GFP_KERNEL); | ||
612 | if (priv == NULL) | ||
613 | return NULL; | ||
614 | |||
615 | priv->i2c = i2c; | ||
616 | priv->dual_master = dual_master; | ||
617 | priv->addr = i2c_address; | ||
618 | priv->xtal_freq = xtal_freq; | ||
619 | |||
620 | info("Fitipower FC0013 successfully attached."); | ||
621 | |||
622 | fe->tuner_priv = priv; | ||
623 | |||
624 | memcpy(&fe->ops.tuner_ops, &fc0013_tuner_ops, | ||
625 | sizeof(struct dvb_tuner_ops)); | ||
626 | |||
627 | return fe; | ||
628 | } | ||
629 | EXPORT_SYMBOL(fc0013_attach); | ||
630 | |||
631 | MODULE_DESCRIPTION("Fitipower FC0013 silicon tuner driver"); | ||
632 | MODULE_AUTHOR("Hans-Frieder Vogt <hfvogt@gmx.net>"); | ||
633 | MODULE_LICENSE("GPL"); | ||
634 | MODULE_VERSION("0.2"); | ||
diff --git a/drivers/media/tuners/fc0013.h b/drivers/media/tuners/fc0013.h new file mode 100644 index 000000000000..594efd64aeec --- /dev/null +++ b/drivers/media/tuners/fc0013.h | |||
@@ -0,0 +1,57 @@ | |||
1 | /* | ||
2 | * Fitipower FC0013 tuner driver | ||
3 | * | ||
4 | * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net> | ||
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 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #ifndef _FC0013_H_ | ||
23 | #define _FC0013_H_ | ||
24 | |||
25 | #include "dvb_frontend.h" | ||
26 | #include "fc001x-common.h" | ||
27 | |||
28 | #if defined(CONFIG_MEDIA_TUNER_FC0013) || \ | ||
29 | (defined(CONFIG_MEDIA_TUNER_FC0013_MODULE) && defined(MODULE)) | ||
30 | extern struct dvb_frontend *fc0013_attach(struct dvb_frontend *fe, | ||
31 | struct i2c_adapter *i2c, | ||
32 | u8 i2c_address, int dual_master, | ||
33 | enum fc001x_xtal_freq xtal_freq); | ||
34 | extern int fc0013_rc_cal_add(struct dvb_frontend *fe, int rc_val); | ||
35 | extern int fc0013_rc_cal_reset(struct dvb_frontend *fe); | ||
36 | #else | ||
37 | static inline struct dvb_frontend *fc0013_attach(struct dvb_frontend *fe, | ||
38 | struct i2c_adapter *i2c, | ||
39 | u8 i2c_address, int dual_master, | ||
40 | enum fc001x_xtal_freq xtal_freq) | ||
41 | { | ||
42 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
43 | return NULL; | ||
44 | } | ||
45 | |||
46 | static inline int fc0013_rc_cal_add(struct dvb_frontend *fe, int rc_val) | ||
47 | { | ||
48 | return 0; | ||
49 | } | ||
50 | |||
51 | static inline int fc0013_rc_cal_reset(struct dvb_frontend *fe) | ||
52 | { | ||
53 | return 0; | ||
54 | } | ||
55 | #endif | ||
56 | |||
57 | #endif | ||
diff --git a/drivers/media/tuners/fc001x-common.h b/drivers/media/tuners/fc001x-common.h new file mode 100644 index 000000000000..718818156934 --- /dev/null +++ b/drivers/media/tuners/fc001x-common.h | |||
@@ -0,0 +1,39 @@ | |||
1 | /* | ||
2 | * Fitipower FC0012 & FC0013 tuner driver - common defines | ||
3 | * | ||
4 | * Copyright (C) 2012 Hans-Frieder Vogt <hfvogt@gmx.net> | ||
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 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef _FC001X_COMMON_H_ | ||
22 | #define _FC001X_COMMON_H_ | ||
23 | |||
24 | enum fc001x_xtal_freq { | ||
25 | FC_XTAL_27_MHZ, /* 27000000 */ | ||
26 | FC_XTAL_28_8_MHZ, /* 28800000 */ | ||
27 | FC_XTAL_36_MHZ, /* 36000000 */ | ||
28 | }; | ||
29 | |||
30 | /* | ||
31 | * enum fc001x_fe_callback_commands - Frontend callbacks | ||
32 | * | ||
33 | * @FC_FE_CALLBACK_VHF_ENABLE: enable VHF or UHF | ||
34 | */ | ||
35 | enum fc001x_fe_callback_commands { | ||
36 | FC_FE_CALLBACK_VHF_ENABLE, | ||
37 | }; | ||
38 | |||
39 | #endif | ||
diff --git a/drivers/media/tuners/max2165.c b/drivers/media/tuners/max2165.c new file mode 100644 index 000000000000..ba84936aafd6 --- /dev/null +++ b/drivers/media/tuners/max2165.c | |||
@@ -0,0 +1,433 @@ | |||
1 | /* | ||
2 | * Driver for Maxim MAX2165 silicon tuner | ||
3 | * | ||
4 | * Copyright (c) 2009 David T. L. Wong <davidtlwong@gmail.com> | ||
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/moduleparam.h> | ||
24 | #include <linux/videodev2.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/dvb/frontend.h> | ||
27 | #include <linux/i2c.h> | ||
28 | #include <linux/slab.h> | ||
29 | |||
30 | #include "dvb_frontend.h" | ||
31 | |||
32 | #include "max2165.h" | ||
33 | #include "max2165_priv.h" | ||
34 | #include "tuner-i2c.h" | ||
35 | |||
36 | #define dprintk(args...) \ | ||
37 | do { \ | ||
38 | if (debug) \ | ||
39 | printk(KERN_DEBUG "max2165: " args); \ | ||
40 | } while (0) | ||
41 | |||
42 | static int debug; | ||
43 | module_param(debug, int, 0644); | ||
44 | MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); | ||
45 | |||
46 | static int max2165_write_reg(struct max2165_priv *priv, u8 reg, u8 data) | ||
47 | { | ||
48 | int ret; | ||
49 | u8 buf[] = { reg, data }; | ||
50 | struct i2c_msg msg = { .flags = 0, .buf = buf, .len = 2 }; | ||
51 | |||
52 | msg.addr = priv->config->i2c_address; | ||
53 | |||
54 | if (debug >= 2) | ||
55 | dprintk("%s: reg=0x%02X, data=0x%02X\n", __func__, reg, data); | ||
56 | |||
57 | ret = i2c_transfer(priv->i2c, &msg, 1); | ||
58 | |||
59 | if (ret != 1) | ||
60 | dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n", | ||
61 | __func__, reg, data, ret); | ||
62 | |||
63 | return (ret != 1) ? -EIO : 0; | ||
64 | } | ||
65 | |||
66 | static int max2165_read_reg(struct max2165_priv *priv, u8 reg, u8 *p_data) | ||
67 | { | ||
68 | int ret; | ||
69 | u8 dev_addr = priv->config->i2c_address; | ||
70 | |||
71 | u8 b0[] = { reg }; | ||
72 | u8 b1[] = { 0 }; | ||
73 | struct i2c_msg msg[] = { | ||
74 | { .addr = dev_addr, .flags = 0, .buf = b0, .len = 1 }, | ||
75 | { .addr = dev_addr, .flags = I2C_M_RD, .buf = b1, .len = 1 }, | ||
76 | }; | ||
77 | |||
78 | ret = i2c_transfer(priv->i2c, msg, 2); | ||
79 | if (ret != 2) { | ||
80 | dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg, ret); | ||
81 | return -EIO; | ||
82 | } | ||
83 | |||
84 | *p_data = b1[0]; | ||
85 | if (debug >= 2) | ||
86 | dprintk("%s: reg=0x%02X, data=0x%02X\n", | ||
87 | __func__, reg, b1[0]); | ||
88 | return 0; | ||
89 | } | ||
90 | |||
91 | static int max2165_mask_write_reg(struct max2165_priv *priv, u8 reg, | ||
92 | u8 mask, u8 data) | ||
93 | { | ||
94 | int ret; | ||
95 | u8 v; | ||
96 | |||
97 | data &= mask; | ||
98 | ret = max2165_read_reg(priv, reg, &v); | ||
99 | if (ret != 0) | ||
100 | return ret; | ||
101 | v &= ~mask; | ||
102 | v |= data; | ||
103 | ret = max2165_write_reg(priv, reg, v); | ||
104 | |||
105 | return ret; | ||
106 | } | ||
107 | |||
108 | static int max2165_read_rom_table(struct max2165_priv *priv) | ||
109 | { | ||
110 | u8 dat[3]; | ||
111 | int i; | ||
112 | |||
113 | for (i = 0; i < 3; i++) { | ||
114 | max2165_write_reg(priv, REG_ROM_TABLE_ADDR, i + 1); | ||
115 | max2165_read_reg(priv, REG_ROM_TABLE_DATA, &dat[i]); | ||
116 | } | ||
117 | |||
118 | priv->tf_ntch_low_cfg = dat[0] >> 4; | ||
119 | priv->tf_ntch_hi_cfg = dat[0] & 0x0F; | ||
120 | priv->tf_balun_low_ref = dat[1] & 0x0F; | ||
121 | priv->tf_balun_hi_ref = dat[1] >> 4; | ||
122 | priv->bb_filter_7mhz_cfg = dat[2] & 0x0F; | ||
123 | priv->bb_filter_8mhz_cfg = dat[2] >> 4; | ||
124 | |||
125 | dprintk("tf_ntch_low_cfg = 0x%X\n", priv->tf_ntch_low_cfg); | ||
126 | dprintk("tf_ntch_hi_cfg = 0x%X\n", priv->tf_ntch_hi_cfg); | ||
127 | dprintk("tf_balun_low_ref = 0x%X\n", priv->tf_balun_low_ref); | ||
128 | dprintk("tf_balun_hi_ref = 0x%X\n", priv->tf_balun_hi_ref); | ||
129 | dprintk("bb_filter_7mhz_cfg = 0x%X\n", priv->bb_filter_7mhz_cfg); | ||
130 | dprintk("bb_filter_8mhz_cfg = 0x%X\n", priv->bb_filter_8mhz_cfg); | ||
131 | |||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | static int max2165_set_osc(struct max2165_priv *priv, u8 osc /*MHz*/) | ||
136 | { | ||
137 | u8 v; | ||
138 | |||
139 | v = (osc / 2); | ||
140 | if (v == 2) | ||
141 | v = 0x7; | ||
142 | else | ||
143 | v -= 8; | ||
144 | |||
145 | max2165_mask_write_reg(priv, REG_PLL_CFG, 0x07, v); | ||
146 | |||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | static int max2165_set_bandwidth(struct max2165_priv *priv, u32 bw) | ||
151 | { | ||
152 | u8 val; | ||
153 | |||
154 | if (bw == 8000000) | ||
155 | val = priv->bb_filter_8mhz_cfg; | ||
156 | else | ||
157 | val = priv->bb_filter_7mhz_cfg; | ||
158 | |||
159 | max2165_mask_write_reg(priv, REG_BASEBAND_CTRL, 0xF0, val << 4); | ||
160 | |||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | int fixpt_div32(u32 dividend, u32 divisor, u32 *quotient, u32 *fraction) | ||
165 | { | ||
166 | u32 remainder; | ||
167 | u32 q, f = 0; | ||
168 | int i; | ||
169 | |||
170 | if (0 == divisor) | ||
171 | return -EINVAL; | ||
172 | |||
173 | q = dividend / divisor; | ||
174 | remainder = dividend - q * divisor; | ||
175 | |||
176 | for (i = 0; i < 31; i++) { | ||
177 | remainder <<= 1; | ||
178 | if (remainder >= divisor) { | ||
179 | f += 1; | ||
180 | remainder -= divisor; | ||
181 | } | ||
182 | f <<= 1; | ||
183 | } | ||
184 | |||
185 | *quotient = q; | ||
186 | *fraction = f; | ||
187 | |||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | static int max2165_set_rf(struct max2165_priv *priv, u32 freq) | ||
192 | { | ||
193 | u8 tf; | ||
194 | u8 tf_ntch; | ||
195 | u32 t; | ||
196 | u32 quotient, fraction; | ||
197 | int ret; | ||
198 | |||
199 | /* Set PLL divider according to RF frequency */ | ||
200 | ret = fixpt_div32(freq / 1000, priv->config->osc_clk * 1000, | ||
201 | "ient, &fraction); | ||
202 | if (ret != 0) | ||
203 | return ret; | ||
204 | |||
205 | /* 20-bit fraction */ | ||
206 | fraction >>= 12; | ||
207 | |||
208 | max2165_write_reg(priv, REG_NDIV_INT, quotient); | ||
209 | max2165_mask_write_reg(priv, REG_NDIV_FRAC2, 0x0F, fraction >> 16); | ||
210 | max2165_write_reg(priv, REG_NDIV_FRAC1, fraction >> 8); | ||
211 | max2165_write_reg(priv, REG_NDIV_FRAC0, fraction); | ||
212 | |||
213 | /* Norch Filter */ | ||
214 | tf_ntch = (freq < 725000000) ? | ||
215 | priv->tf_ntch_low_cfg : priv->tf_ntch_hi_cfg; | ||
216 | |||
217 | /* Tracking filter balun */ | ||
218 | t = priv->tf_balun_low_ref; | ||
219 | t += (priv->tf_balun_hi_ref - priv->tf_balun_low_ref) | ||
220 | * (freq / 1000 - 470000) / (780000 - 470000); | ||
221 | |||
222 | tf = t; | ||
223 | dprintk("tf = %X\n", tf); | ||
224 | tf |= tf_ntch << 4; | ||
225 | |||
226 | max2165_write_reg(priv, REG_TRACK_FILTER, tf); | ||
227 | |||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | static void max2165_debug_status(struct max2165_priv *priv) | ||
232 | { | ||
233 | u8 status, autotune; | ||
234 | u8 auto_vco_success, auto_vco_active; | ||
235 | u8 pll_locked; | ||
236 | u8 dc_offset_low, dc_offset_hi; | ||
237 | u8 signal_lv_over_threshold; | ||
238 | u8 vco, vco_sub_band, adc; | ||
239 | |||
240 | max2165_read_reg(priv, REG_STATUS, &status); | ||
241 | max2165_read_reg(priv, REG_AUTOTUNE, &autotune); | ||
242 | |||
243 | auto_vco_success = (status >> 6) & 0x01; | ||
244 | auto_vco_active = (status >> 5) & 0x01; | ||
245 | pll_locked = (status >> 4) & 0x01; | ||
246 | dc_offset_low = (status >> 3) & 0x01; | ||
247 | dc_offset_hi = (status >> 2) & 0x01; | ||
248 | signal_lv_over_threshold = status & 0x01; | ||
249 | |||
250 | vco = autotune >> 6; | ||
251 | vco_sub_band = (autotune >> 3) & 0x7; | ||
252 | adc = autotune & 0x7; | ||
253 | |||
254 | dprintk("auto VCO active: %d, auto VCO success: %d\n", | ||
255 | auto_vco_active, auto_vco_success); | ||
256 | dprintk("PLL locked: %d\n", pll_locked); | ||
257 | dprintk("DC offset low: %d, DC offset high: %d\n", | ||
258 | dc_offset_low, dc_offset_hi); | ||
259 | dprintk("Signal lvl over threshold: %d\n", signal_lv_over_threshold); | ||
260 | dprintk("VCO: %d, VCO Sub-band: %d, ADC: %d\n", vco, vco_sub_band, adc); | ||
261 | } | ||
262 | |||
263 | static int max2165_set_params(struct dvb_frontend *fe) | ||
264 | { | ||
265 | struct max2165_priv *priv = fe->tuner_priv; | ||
266 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
267 | int ret; | ||
268 | |||
269 | switch (c->bandwidth_hz) { | ||
270 | case 7000000: | ||
271 | case 8000000: | ||
272 | priv->frequency = c->frequency; | ||
273 | break; | ||
274 | default: | ||
275 | printk(KERN_INFO "MAX2165: bandwidth %d Hz not supported.\n", | ||
276 | c->bandwidth_hz); | ||
277 | return -EINVAL; | ||
278 | } | ||
279 | |||
280 | dprintk("%s() frequency=%d\n", __func__, c->frequency); | ||
281 | |||
282 | if (fe->ops.i2c_gate_ctrl) | ||
283 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
284 | max2165_set_bandwidth(priv, c->bandwidth_hz); | ||
285 | ret = max2165_set_rf(priv, priv->frequency); | ||
286 | mdelay(50); | ||
287 | max2165_debug_status(priv); | ||
288 | if (fe->ops.i2c_gate_ctrl) | ||
289 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
290 | |||
291 | if (ret != 0) | ||
292 | return -EREMOTEIO; | ||
293 | |||
294 | return 0; | ||
295 | } | ||
296 | |||
297 | static int max2165_get_frequency(struct dvb_frontend *fe, u32 *freq) | ||
298 | { | ||
299 | struct max2165_priv *priv = fe->tuner_priv; | ||
300 | dprintk("%s()\n", __func__); | ||
301 | *freq = priv->frequency; | ||
302 | return 0; | ||
303 | } | ||
304 | |||
305 | static int max2165_get_bandwidth(struct dvb_frontend *fe, u32 *bw) | ||
306 | { | ||
307 | struct max2165_priv *priv = fe->tuner_priv; | ||
308 | dprintk("%s()\n", __func__); | ||
309 | |||
310 | *bw = priv->bandwidth; | ||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | static int max2165_get_status(struct dvb_frontend *fe, u32 *status) | ||
315 | { | ||
316 | struct max2165_priv *priv = fe->tuner_priv; | ||
317 | u16 lock_status = 0; | ||
318 | |||
319 | dprintk("%s()\n", __func__); | ||
320 | |||
321 | if (fe->ops.i2c_gate_ctrl) | ||
322 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
323 | |||
324 | max2165_debug_status(priv); | ||
325 | *status = lock_status; | ||
326 | |||
327 | if (fe->ops.i2c_gate_ctrl) | ||
328 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
329 | |||
330 | return 0; | ||
331 | } | ||
332 | |||
333 | static int max2165_sleep(struct dvb_frontend *fe) | ||
334 | { | ||
335 | dprintk("%s()\n", __func__); | ||
336 | return 0; | ||
337 | } | ||
338 | |||
339 | static int max2165_init(struct dvb_frontend *fe) | ||
340 | { | ||
341 | struct max2165_priv *priv = fe->tuner_priv; | ||
342 | dprintk("%s()\n", __func__); | ||
343 | |||
344 | if (fe->ops.i2c_gate_ctrl) | ||
345 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
346 | |||
347 | /* Setup initial values */ | ||
348 | /* Fractional Mode on */ | ||
349 | max2165_write_reg(priv, REG_NDIV_FRAC2, 0x18); | ||
350 | /* LNA on */ | ||
351 | max2165_write_reg(priv, REG_LNA, 0x01); | ||
352 | max2165_write_reg(priv, REG_PLL_CFG, 0x7A); | ||
353 | max2165_write_reg(priv, REG_TEST, 0x08); | ||
354 | max2165_write_reg(priv, REG_SHUTDOWN, 0x40); | ||
355 | max2165_write_reg(priv, REG_VCO_CTRL, 0x84); | ||
356 | max2165_write_reg(priv, REG_BASEBAND_CTRL, 0xC3); | ||
357 | max2165_write_reg(priv, REG_DC_OFFSET_CTRL, 0x75); | ||
358 | max2165_write_reg(priv, REG_DC_OFFSET_DAC, 0x00); | ||
359 | max2165_write_reg(priv, REG_ROM_TABLE_ADDR, 0x00); | ||
360 | |||
361 | max2165_set_osc(priv, priv->config->osc_clk); | ||
362 | |||
363 | max2165_read_rom_table(priv); | ||
364 | |||
365 | max2165_set_bandwidth(priv, 8000000); | ||
366 | |||
367 | if (fe->ops.i2c_gate_ctrl) | ||
368 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
369 | |||
370 | return 0; | ||
371 | } | ||
372 | |||
373 | static int max2165_release(struct dvb_frontend *fe) | ||
374 | { | ||
375 | struct max2165_priv *priv = fe->tuner_priv; | ||
376 | dprintk("%s()\n", __func__); | ||
377 | |||
378 | kfree(priv); | ||
379 | fe->tuner_priv = NULL; | ||
380 | |||
381 | return 0; | ||
382 | } | ||
383 | |||
384 | static const struct dvb_tuner_ops max2165_tuner_ops = { | ||
385 | .info = { | ||
386 | .name = "Maxim MAX2165", | ||
387 | .frequency_min = 470000000, | ||
388 | .frequency_max = 780000000, | ||
389 | .frequency_step = 50000, | ||
390 | }, | ||
391 | |||
392 | .release = max2165_release, | ||
393 | .init = max2165_init, | ||
394 | .sleep = max2165_sleep, | ||
395 | |||
396 | .set_params = max2165_set_params, | ||
397 | .set_analog_params = NULL, | ||
398 | .get_frequency = max2165_get_frequency, | ||
399 | .get_bandwidth = max2165_get_bandwidth, | ||
400 | .get_status = max2165_get_status | ||
401 | }; | ||
402 | |||
403 | struct dvb_frontend *max2165_attach(struct dvb_frontend *fe, | ||
404 | struct i2c_adapter *i2c, | ||
405 | struct max2165_config *cfg) | ||
406 | { | ||
407 | struct max2165_priv *priv = NULL; | ||
408 | |||
409 | dprintk("%s(%d-%04x)\n", __func__, | ||
410 | i2c ? i2c_adapter_id(i2c) : -1, | ||
411 | cfg ? cfg->i2c_address : -1); | ||
412 | |||
413 | priv = kzalloc(sizeof(struct max2165_priv), GFP_KERNEL); | ||
414 | if (priv == NULL) | ||
415 | return NULL; | ||
416 | |||
417 | memcpy(&fe->ops.tuner_ops, &max2165_tuner_ops, | ||
418 | sizeof(struct dvb_tuner_ops)); | ||
419 | |||
420 | priv->config = cfg; | ||
421 | priv->i2c = i2c; | ||
422 | fe->tuner_priv = priv; | ||
423 | |||
424 | max2165_init(fe); | ||
425 | max2165_debug_status(priv); | ||
426 | |||
427 | return fe; | ||
428 | } | ||
429 | EXPORT_SYMBOL(max2165_attach); | ||
430 | |||
431 | MODULE_AUTHOR("David T. L. Wong <davidtlwong@gmail.com>"); | ||
432 | MODULE_DESCRIPTION("Maxim MAX2165 silicon tuner driver"); | ||
433 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/tuners/max2165.h b/drivers/media/tuners/max2165.h new file mode 100644 index 000000000000..c063c36a93d3 --- /dev/null +++ b/drivers/media/tuners/max2165.h | |||
@@ -0,0 +1,48 @@ | |||
1 | /* | ||
2 | * Driver for Maxim MAX2165 silicon tuner | ||
3 | * | ||
4 | * Copyright (c) 2009 David T. L. Wong <davidtlwong@gmail.com> | ||
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 __MAX2165_H__ | ||
23 | #define __MAX2165_H__ | ||
24 | |||
25 | struct dvb_frontend; | ||
26 | struct i2c_adapter; | ||
27 | |||
28 | struct max2165_config { | ||
29 | u8 i2c_address; | ||
30 | u8 osc_clk; /* in MHz, selectable values: 4,16,18,20,22,24,26,28 */ | ||
31 | }; | ||
32 | |||
33 | #if defined(CONFIG_MEDIA_TUNER_MAX2165) || \ | ||
34 | (defined(CONFIG_MEDIA_TUNER_MAX2165_MODULE) && defined(MODULE)) | ||
35 | extern struct dvb_frontend *max2165_attach(struct dvb_frontend *fe, | ||
36 | struct i2c_adapter *i2c, | ||
37 | struct max2165_config *cfg); | ||
38 | #else | ||
39 | static inline struct dvb_frontend *max2165_attach(struct dvb_frontend *fe, | ||
40 | struct i2c_adapter *i2c, | ||
41 | struct max2165_config *cfg) | ||
42 | { | ||
43 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
44 | return NULL; | ||
45 | } | ||
46 | #endif | ||
47 | |||
48 | #endif | ||
diff --git a/drivers/media/tuners/max2165_priv.h b/drivers/media/tuners/max2165_priv.h new file mode 100644 index 000000000000..91bbe021a08d --- /dev/null +++ b/drivers/media/tuners/max2165_priv.h | |||
@@ -0,0 +1,60 @@ | |||
1 | /* | ||
2 | * Driver for Maxim MAX2165 silicon tuner | ||
3 | * | ||
4 | * Copyright (c) 2009 David T. L. Wong <davidtlwong@gmail.com> | ||
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 __MAX2165_PRIV_H__ | ||
23 | #define __MAX2165_PRIV_H__ | ||
24 | |||
25 | #define REG_NDIV_INT 0x00 | ||
26 | #define REG_NDIV_FRAC2 0x01 | ||
27 | #define REG_NDIV_FRAC1 0x02 | ||
28 | #define REG_NDIV_FRAC0 0x03 | ||
29 | #define REG_TRACK_FILTER 0x04 | ||
30 | #define REG_LNA 0x05 | ||
31 | #define REG_PLL_CFG 0x06 | ||
32 | #define REG_TEST 0x07 | ||
33 | #define REG_SHUTDOWN 0x08 | ||
34 | #define REG_VCO_CTRL 0x09 | ||
35 | #define REG_BASEBAND_CTRL 0x0A | ||
36 | #define REG_DC_OFFSET_CTRL 0x0B | ||
37 | #define REG_DC_OFFSET_DAC 0x0C | ||
38 | #define REG_ROM_TABLE_ADDR 0x0D | ||
39 | |||
40 | /* Read Only Registers */ | ||
41 | #define REG_ROM_TABLE_DATA 0x10 | ||
42 | #define REG_STATUS 0x11 | ||
43 | #define REG_AUTOTUNE 0x12 | ||
44 | |||
45 | struct max2165_priv { | ||
46 | struct max2165_config *config; | ||
47 | struct i2c_adapter *i2c; | ||
48 | |||
49 | u32 frequency; | ||
50 | u32 bandwidth; | ||
51 | |||
52 | u8 tf_ntch_low_cfg; | ||
53 | u8 tf_ntch_hi_cfg; | ||
54 | u8 tf_balun_low_ref; | ||
55 | u8 tf_balun_hi_ref; | ||
56 | u8 bb_filter_7mhz_cfg; | ||
57 | u8 bb_filter_8mhz_cfg; | ||
58 | }; | ||
59 | |||
60 | #endif | ||
diff --git a/drivers/media/tuners/mc44s803.c b/drivers/media/tuners/mc44s803.c new file mode 100644 index 000000000000..5ddce7e326f7 --- /dev/null +++ b/drivers/media/tuners/mc44s803.c | |||
@@ -0,0 +1,372 @@ | |||
1 | /* | ||
2 | * Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner | ||
3 | * | ||
4 | * Copyright (c) 2009 Jochen Friedrich <jochen@scram.de> | ||
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/delay.h> | ||
24 | #include <linux/dvb/frontend.h> | ||
25 | #include <linux/i2c.h> | ||
26 | #include <linux/slab.h> | ||
27 | |||
28 | #include "dvb_frontend.h" | ||
29 | |||
30 | #include "mc44s803.h" | ||
31 | #include "mc44s803_priv.h" | ||
32 | |||
33 | #define mc_printk(level, format, arg...) \ | ||
34 | printk(level "mc44s803: " format , ## arg) | ||
35 | |||
36 | /* Writes a single register */ | ||
37 | static int mc44s803_writereg(struct mc44s803_priv *priv, u32 val) | ||
38 | { | ||
39 | u8 buf[3]; | ||
40 | struct i2c_msg msg = { | ||
41 | .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 3 | ||
42 | }; | ||
43 | |||
44 | buf[0] = (val & 0xff0000) >> 16; | ||
45 | buf[1] = (val & 0xff00) >> 8; | ||
46 | buf[2] = (val & 0xff); | ||
47 | |||
48 | if (i2c_transfer(priv->i2c, &msg, 1) != 1) { | ||
49 | mc_printk(KERN_WARNING, "I2C write failed\n"); | ||
50 | return -EREMOTEIO; | ||
51 | } | ||
52 | return 0; | ||
53 | } | ||
54 | |||
55 | /* Reads a single register */ | ||
56 | static int mc44s803_readreg(struct mc44s803_priv *priv, u8 reg, u32 *val) | ||
57 | { | ||
58 | u32 wval; | ||
59 | u8 buf[3]; | ||
60 | int ret; | ||
61 | struct i2c_msg msg[] = { | ||
62 | { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, | ||
63 | .buf = buf, .len = 3 }, | ||
64 | }; | ||
65 | |||
66 | wval = MC44S803_REG_SM(MC44S803_REG_DATAREG, MC44S803_ADDR) | | ||
67 | MC44S803_REG_SM(reg, MC44S803_D); | ||
68 | |||
69 | ret = mc44s803_writereg(priv, wval); | ||
70 | if (ret) | ||
71 | return ret; | ||
72 | |||
73 | if (i2c_transfer(priv->i2c, msg, 1) != 1) { | ||
74 | mc_printk(KERN_WARNING, "I2C read failed\n"); | ||
75 | return -EREMOTEIO; | ||
76 | } | ||
77 | |||
78 | *val = (buf[0] << 16) | (buf[1] << 8) | buf[2]; | ||
79 | |||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | static int mc44s803_release(struct dvb_frontend *fe) | ||
84 | { | ||
85 | struct mc44s803_priv *priv = fe->tuner_priv; | ||
86 | |||
87 | fe->tuner_priv = NULL; | ||
88 | kfree(priv); | ||
89 | |||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | static int mc44s803_init(struct dvb_frontend *fe) | ||
94 | { | ||
95 | struct mc44s803_priv *priv = fe->tuner_priv; | ||
96 | u32 val; | ||
97 | int err; | ||
98 | |||
99 | if (fe->ops.i2c_gate_ctrl) | ||
100 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
101 | |||
102 | /* Reset chip */ | ||
103 | val = MC44S803_REG_SM(MC44S803_REG_RESET, MC44S803_ADDR) | | ||
104 | MC44S803_REG_SM(1, MC44S803_RS); | ||
105 | |||
106 | err = mc44s803_writereg(priv, val); | ||
107 | if (err) | ||
108 | goto exit; | ||
109 | |||
110 | val = MC44S803_REG_SM(MC44S803_REG_RESET, MC44S803_ADDR); | ||
111 | |||
112 | err = mc44s803_writereg(priv, val); | ||
113 | if (err) | ||
114 | goto exit; | ||
115 | |||
116 | /* Power Up and Start Osc */ | ||
117 | |||
118 | val = MC44S803_REG_SM(MC44S803_REG_REFOSC, MC44S803_ADDR) | | ||
119 | MC44S803_REG_SM(0xC0, MC44S803_REFOSC) | | ||
120 | MC44S803_REG_SM(1, MC44S803_OSCSEL); | ||
121 | |||
122 | err = mc44s803_writereg(priv, val); | ||
123 | if (err) | ||
124 | goto exit; | ||
125 | |||
126 | val = MC44S803_REG_SM(MC44S803_REG_POWER, MC44S803_ADDR) | | ||
127 | MC44S803_REG_SM(0x200, MC44S803_POWER); | ||
128 | |||
129 | err = mc44s803_writereg(priv, val); | ||
130 | if (err) | ||
131 | goto exit; | ||
132 | |||
133 | msleep(10); | ||
134 | |||
135 | val = MC44S803_REG_SM(MC44S803_REG_REFOSC, MC44S803_ADDR) | | ||
136 | MC44S803_REG_SM(0x40, MC44S803_REFOSC) | | ||
137 | MC44S803_REG_SM(1, MC44S803_OSCSEL); | ||
138 | |||
139 | err = mc44s803_writereg(priv, val); | ||
140 | if (err) | ||
141 | goto exit; | ||
142 | |||
143 | msleep(20); | ||
144 | |||
145 | /* Setup Mixer */ | ||
146 | |||
147 | val = MC44S803_REG_SM(MC44S803_REG_MIXER, MC44S803_ADDR) | | ||
148 | MC44S803_REG_SM(1, MC44S803_TRI_STATE) | | ||
149 | MC44S803_REG_SM(0x7F, MC44S803_MIXER_RES); | ||
150 | |||
151 | err = mc44s803_writereg(priv, val); | ||
152 | if (err) | ||
153 | goto exit; | ||
154 | |||
155 | /* Setup Cirquit Adjust */ | ||
156 | |||
157 | val = MC44S803_REG_SM(MC44S803_REG_CIRCADJ, MC44S803_ADDR) | | ||
158 | MC44S803_REG_SM(1, MC44S803_G1) | | ||
159 | MC44S803_REG_SM(1, MC44S803_G3) | | ||
160 | MC44S803_REG_SM(0x3, MC44S803_CIRCADJ_RES) | | ||
161 | MC44S803_REG_SM(1, MC44S803_G6) | | ||
162 | MC44S803_REG_SM(priv->cfg->dig_out, MC44S803_S1) | | ||
163 | MC44S803_REG_SM(0x3, MC44S803_LP) | | ||
164 | MC44S803_REG_SM(1, MC44S803_CLRF) | | ||
165 | MC44S803_REG_SM(1, MC44S803_CLIF); | ||
166 | |||
167 | err = mc44s803_writereg(priv, val); | ||
168 | if (err) | ||
169 | goto exit; | ||
170 | |||
171 | val = MC44S803_REG_SM(MC44S803_REG_CIRCADJ, MC44S803_ADDR) | | ||
172 | MC44S803_REG_SM(1, MC44S803_G1) | | ||
173 | MC44S803_REG_SM(1, MC44S803_G3) | | ||
174 | MC44S803_REG_SM(0x3, MC44S803_CIRCADJ_RES) | | ||
175 | MC44S803_REG_SM(1, MC44S803_G6) | | ||
176 | MC44S803_REG_SM(priv->cfg->dig_out, MC44S803_S1) | | ||
177 | MC44S803_REG_SM(0x3, MC44S803_LP); | ||
178 | |||
179 | err = mc44s803_writereg(priv, val); | ||
180 | if (err) | ||
181 | goto exit; | ||
182 | |||
183 | /* Setup Digtune */ | ||
184 | |||
185 | val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) | | ||
186 | MC44S803_REG_SM(3, MC44S803_XOD); | ||
187 | |||
188 | err = mc44s803_writereg(priv, val); | ||
189 | if (err) | ||
190 | goto exit; | ||
191 | |||
192 | /* Setup AGC */ | ||
193 | |||
194 | val = MC44S803_REG_SM(MC44S803_REG_LNAAGC, MC44S803_ADDR) | | ||
195 | MC44S803_REG_SM(1, MC44S803_AT1) | | ||
196 | MC44S803_REG_SM(1, MC44S803_AT2) | | ||
197 | MC44S803_REG_SM(1, MC44S803_AGC_AN_DIG) | | ||
198 | MC44S803_REG_SM(1, MC44S803_AGC_READ_EN) | | ||
199 | MC44S803_REG_SM(1, MC44S803_LNA0); | ||
200 | |||
201 | err = mc44s803_writereg(priv, val); | ||
202 | if (err) | ||
203 | goto exit; | ||
204 | |||
205 | if (fe->ops.i2c_gate_ctrl) | ||
206 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
207 | return 0; | ||
208 | |||
209 | exit: | ||
210 | if (fe->ops.i2c_gate_ctrl) | ||
211 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
212 | |||
213 | mc_printk(KERN_WARNING, "I/O Error\n"); | ||
214 | return err; | ||
215 | } | ||
216 | |||
217 | static int mc44s803_set_params(struct dvb_frontend *fe) | ||
218 | { | ||
219 | struct mc44s803_priv *priv = fe->tuner_priv; | ||
220 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
221 | u32 r1, r2, n1, n2, lo1, lo2, freq, val; | ||
222 | int err; | ||
223 | |||
224 | priv->frequency = c->frequency; | ||
225 | |||
226 | r1 = MC44S803_OSC / 1000000; | ||
227 | r2 = MC44S803_OSC / 100000; | ||
228 | |||
229 | n1 = (c->frequency + MC44S803_IF1 + 500000) / 1000000; | ||
230 | freq = MC44S803_OSC / r1 * n1; | ||
231 | lo1 = ((60 * n1) + (r1 / 2)) / r1; | ||
232 | freq = freq - c->frequency; | ||
233 | |||
234 | n2 = (freq - MC44S803_IF2 + 50000) / 100000; | ||
235 | lo2 = ((60 * n2) + (r2 / 2)) / r2; | ||
236 | |||
237 | if (fe->ops.i2c_gate_ctrl) | ||
238 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
239 | |||
240 | val = MC44S803_REG_SM(MC44S803_REG_REFDIV, MC44S803_ADDR) | | ||
241 | MC44S803_REG_SM(r1-1, MC44S803_R1) | | ||
242 | MC44S803_REG_SM(r2-1, MC44S803_R2) | | ||
243 | MC44S803_REG_SM(1, MC44S803_REFBUF_EN); | ||
244 | |||
245 | err = mc44s803_writereg(priv, val); | ||
246 | if (err) | ||
247 | goto exit; | ||
248 | |||
249 | val = MC44S803_REG_SM(MC44S803_REG_LO1, MC44S803_ADDR) | | ||
250 | MC44S803_REG_SM(n1-2, MC44S803_LO1); | ||
251 | |||
252 | err = mc44s803_writereg(priv, val); | ||
253 | if (err) | ||
254 | goto exit; | ||
255 | |||
256 | val = MC44S803_REG_SM(MC44S803_REG_LO2, MC44S803_ADDR) | | ||
257 | MC44S803_REG_SM(n2-2, MC44S803_LO2); | ||
258 | |||
259 | err = mc44s803_writereg(priv, val); | ||
260 | if (err) | ||
261 | goto exit; | ||
262 | |||
263 | val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) | | ||
264 | MC44S803_REG_SM(1, MC44S803_DA) | | ||
265 | MC44S803_REG_SM(lo1, MC44S803_LO_REF) | | ||
266 | MC44S803_REG_SM(1, MC44S803_AT); | ||
267 | |||
268 | err = mc44s803_writereg(priv, val); | ||
269 | if (err) | ||
270 | goto exit; | ||
271 | |||
272 | val = MC44S803_REG_SM(MC44S803_REG_DIGTUNE, MC44S803_ADDR) | | ||
273 | MC44S803_REG_SM(2, MC44S803_DA) | | ||
274 | MC44S803_REG_SM(lo2, MC44S803_LO_REF) | | ||
275 | MC44S803_REG_SM(1, MC44S803_AT); | ||
276 | |||
277 | err = mc44s803_writereg(priv, val); | ||
278 | if (err) | ||
279 | goto exit; | ||
280 | |||
281 | if (fe->ops.i2c_gate_ctrl) | ||
282 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
283 | |||
284 | return 0; | ||
285 | |||
286 | exit: | ||
287 | if (fe->ops.i2c_gate_ctrl) | ||
288 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
289 | |||
290 | mc_printk(KERN_WARNING, "I/O Error\n"); | ||
291 | return err; | ||
292 | } | ||
293 | |||
294 | static int mc44s803_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
295 | { | ||
296 | struct mc44s803_priv *priv = fe->tuner_priv; | ||
297 | *frequency = priv->frequency; | ||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | static const struct dvb_tuner_ops mc44s803_tuner_ops = { | ||
302 | .info = { | ||
303 | .name = "Freescale MC44S803", | ||
304 | .frequency_min = 48000000, | ||
305 | .frequency_max = 1000000000, | ||
306 | .frequency_step = 100000, | ||
307 | }, | ||
308 | |||
309 | .release = mc44s803_release, | ||
310 | .init = mc44s803_init, | ||
311 | .set_params = mc44s803_set_params, | ||
312 | .get_frequency = mc44s803_get_frequency | ||
313 | }; | ||
314 | |||
315 | /* This functions tries to identify a MC44S803 tuner by reading the ID | ||
316 | register. This is hasty. */ | ||
317 | struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe, | ||
318 | struct i2c_adapter *i2c, struct mc44s803_config *cfg) | ||
319 | { | ||
320 | struct mc44s803_priv *priv; | ||
321 | u32 reg; | ||
322 | u8 id; | ||
323 | int ret; | ||
324 | |||
325 | reg = 0; | ||
326 | |||
327 | priv = kzalloc(sizeof(struct mc44s803_priv), GFP_KERNEL); | ||
328 | if (priv == NULL) | ||
329 | return NULL; | ||
330 | |||
331 | priv->cfg = cfg; | ||
332 | priv->i2c = i2c; | ||
333 | priv->fe = fe; | ||
334 | |||
335 | if (fe->ops.i2c_gate_ctrl) | ||
336 | fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ | ||
337 | |||
338 | ret = mc44s803_readreg(priv, MC44S803_REG_ID, ®); | ||
339 | if (ret) | ||
340 | goto error; | ||
341 | |||
342 | id = MC44S803_REG_MS(reg, MC44S803_ID); | ||
343 | |||
344 | if (id != 0x14) { | ||
345 | mc_printk(KERN_ERR, "unsupported ID " | ||
346 | "(%x should be 0x14)\n", id); | ||
347 | goto error; | ||
348 | } | ||
349 | |||
350 | mc_printk(KERN_INFO, "successfully identified (ID = %x)\n", id); | ||
351 | memcpy(&fe->ops.tuner_ops, &mc44s803_tuner_ops, | ||
352 | sizeof(struct dvb_tuner_ops)); | ||
353 | |||
354 | fe->tuner_priv = priv; | ||
355 | |||
356 | if (fe->ops.i2c_gate_ctrl) | ||
357 | fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ | ||
358 | |||
359 | return fe; | ||
360 | |||
361 | error: | ||
362 | if (fe->ops.i2c_gate_ctrl) | ||
363 | fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ | ||
364 | |||
365 | kfree(priv); | ||
366 | return NULL; | ||
367 | } | ||
368 | EXPORT_SYMBOL(mc44s803_attach); | ||
369 | |||
370 | MODULE_AUTHOR("Jochen Friedrich"); | ||
371 | MODULE_DESCRIPTION("Freescale MC44S803 silicon tuner driver"); | ||
372 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/tuners/mc44s803.h b/drivers/media/tuners/mc44s803.h new file mode 100644 index 000000000000..34f3892d3f6d --- /dev/null +++ b/drivers/media/tuners/mc44s803.h | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | * Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner | ||
3 | * | ||
4 | * Copyright (c) 2009 Jochen Friedrich <jochen@scram.de> | ||
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 MC44S803_H | ||
23 | #define MC44S803_H | ||
24 | |||
25 | struct dvb_frontend; | ||
26 | struct i2c_adapter; | ||
27 | |||
28 | struct mc44s803_config { | ||
29 | u8 i2c_address; | ||
30 | u8 dig_out; | ||
31 | }; | ||
32 | |||
33 | #if defined(CONFIG_MEDIA_TUNER_MC44S803) || \ | ||
34 | (defined(CONFIG_MEDIA_TUNER_MC44S803_MODULE) && defined(MODULE)) | ||
35 | extern struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe, | ||
36 | struct i2c_adapter *i2c, struct mc44s803_config *cfg); | ||
37 | #else | ||
38 | static inline struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe, | ||
39 | struct i2c_adapter *i2c, struct mc44s803_config *cfg) | ||
40 | { | ||
41 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
42 | return NULL; | ||
43 | } | ||
44 | #endif /* CONFIG_MEDIA_TUNER_MC44S803 */ | ||
45 | |||
46 | #endif | ||
diff --git a/drivers/media/tuners/mc44s803_priv.h b/drivers/media/tuners/mc44s803_priv.h new file mode 100644 index 000000000000..14a92780906d --- /dev/null +++ b/drivers/media/tuners/mc44s803_priv.h | |||
@@ -0,0 +1,208 @@ | |||
1 | /* | ||
2 | * Driver for Freescale MC44S803 Low Power CMOS Broadband Tuner | ||
3 | * | ||
4 | * Copyright (c) 2009 Jochen Friedrich <jochen@scram.de> | ||
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 MC44S803_PRIV_H | ||
23 | #define MC44S803_PRIV_H | ||
24 | |||
25 | /* This driver is based on the information available in the datasheet | ||
26 | http://www.freescale.com/files/rf_if/doc/data_sheet/MC44S803.pdf | ||
27 | |||
28 | SPI or I2C Address : 0xc0-0xc6 | ||
29 | |||
30 | Reg.No | Function | ||
31 | ------------------------------------------- | ||
32 | 00 | Power Down | ||
33 | 01 | Reference Oszillator | ||
34 | 02 | Reference Dividers | ||
35 | 03 | Mixer and Reference Buffer | ||
36 | 04 | Reset/Serial Out | ||
37 | 05 | LO 1 | ||
38 | 06 | LO 2 | ||
39 | 07 | Circuit Adjust | ||
40 | 08 | Test | ||
41 | 09 | Digital Tune | ||
42 | 0A | LNA AGC | ||
43 | 0B | Data Register Address | ||
44 | 0C | Regulator Test | ||
45 | 0D | VCO Test | ||
46 | 0E | LNA Gain/Input Power | ||
47 | 0F | ID Bits | ||
48 | |||
49 | */ | ||
50 | |||
51 | #define MC44S803_OSC 26000000 /* 26 MHz */ | ||
52 | #define MC44S803_IF1 1086000000 /* 1086 MHz */ | ||
53 | #define MC44S803_IF2 36125000 /* 36.125 MHz */ | ||
54 | |||
55 | #define MC44S803_REG_POWER 0 | ||
56 | #define MC44S803_REG_REFOSC 1 | ||
57 | #define MC44S803_REG_REFDIV 2 | ||
58 | #define MC44S803_REG_MIXER 3 | ||
59 | #define MC44S803_REG_RESET 4 | ||
60 | #define MC44S803_REG_LO1 5 | ||
61 | #define MC44S803_REG_LO2 6 | ||
62 | #define MC44S803_REG_CIRCADJ 7 | ||
63 | #define MC44S803_REG_TEST 8 | ||
64 | #define MC44S803_REG_DIGTUNE 9 | ||
65 | #define MC44S803_REG_LNAAGC 0x0A | ||
66 | #define MC44S803_REG_DATAREG 0x0B | ||
67 | #define MC44S803_REG_REGTEST 0x0C | ||
68 | #define MC44S803_REG_VCOTEST 0x0D | ||
69 | #define MC44S803_REG_LNAGAIN 0x0E | ||
70 | #define MC44S803_REG_ID 0x0F | ||
71 | |||
72 | /* Register definitions */ | ||
73 | #define MC44S803_ADDR 0x0F | ||
74 | #define MC44S803_ADDR_S 0 | ||
75 | /* REG_POWER */ | ||
76 | #define MC44S803_POWER 0xFFFFF0 | ||
77 | #define MC44S803_POWER_S 4 | ||
78 | /* REG_REFOSC */ | ||
79 | #define MC44S803_REFOSC 0x1FF0 | ||
80 | #define MC44S803_REFOSC_S 4 | ||
81 | #define MC44S803_OSCSEL 0x2000 | ||
82 | #define MC44S803_OSCSEL_S 13 | ||
83 | /* REG_REFDIV */ | ||
84 | #define MC44S803_R2 0x1FF0 | ||
85 | #define MC44S803_R2_S 4 | ||
86 | #define MC44S803_REFBUF_EN 0x2000 | ||
87 | #define MC44S803_REFBUF_EN_S 13 | ||
88 | #define MC44S803_R1 0x7C000 | ||
89 | #define MC44S803_R1_S 14 | ||
90 | /* REG_MIXER */ | ||
91 | #define MC44S803_R3 0x70 | ||
92 | #define MC44S803_R3_S 4 | ||
93 | #define MC44S803_MUX3 0x80 | ||
94 | #define MC44S803_MUX3_S 7 | ||
95 | #define MC44S803_MUX4 0x100 | ||
96 | #define MC44S803_MUX4_S 8 | ||
97 | #define MC44S803_OSC_SCR 0x200 | ||
98 | #define MC44S803_OSC_SCR_S 9 | ||
99 | #define MC44S803_TRI_STATE 0x400 | ||
100 | #define MC44S803_TRI_STATE_S 10 | ||
101 | #define MC44S803_BUF_GAIN 0x800 | ||
102 | #define MC44S803_BUF_GAIN_S 11 | ||
103 | #define MC44S803_BUF_IO 0x1000 | ||
104 | #define MC44S803_BUF_IO_S 12 | ||
105 | #define MC44S803_MIXER_RES 0xFE000 | ||
106 | #define MC44S803_MIXER_RES_S 13 | ||
107 | /* REG_RESET */ | ||
108 | #define MC44S803_RS 0x10 | ||
109 | #define MC44S803_RS_S 4 | ||
110 | #define MC44S803_SO 0x20 | ||
111 | #define MC44S803_SO_S 5 | ||
112 | /* REG_LO1 */ | ||
113 | #define MC44S803_LO1 0xFFF0 | ||
114 | #define MC44S803_LO1_S 4 | ||
115 | /* REG_LO2 */ | ||
116 | #define MC44S803_LO2 0x7FFF0 | ||
117 | #define MC44S803_LO2_S 4 | ||
118 | /* REG_CIRCADJ */ | ||
119 | #define MC44S803_G1 0x20 | ||
120 | #define MC44S803_G1_S 5 | ||
121 | #define MC44S803_G3 0x80 | ||
122 | #define MC44S803_G3_S 7 | ||
123 | #define MC44S803_CIRCADJ_RES 0x300 | ||
124 | #define MC44S803_CIRCADJ_RES_S 8 | ||
125 | #define MC44S803_G6 0x400 | ||
126 | #define MC44S803_G6_S 10 | ||
127 | #define MC44S803_G7 0x800 | ||
128 | #define MC44S803_G7_S 11 | ||
129 | #define MC44S803_S1 0x1000 | ||
130 | #define MC44S803_S1_S 12 | ||
131 | #define MC44S803_LP 0x7E000 | ||
132 | #define MC44S803_LP_S 13 | ||
133 | #define MC44S803_CLRF 0x80000 | ||
134 | #define MC44S803_CLRF_S 19 | ||
135 | #define MC44S803_CLIF 0x100000 | ||
136 | #define MC44S803_CLIF_S 20 | ||
137 | /* REG_TEST */ | ||
138 | /* REG_DIGTUNE */ | ||
139 | #define MC44S803_DA 0xF0 | ||
140 | #define MC44S803_DA_S 4 | ||
141 | #define MC44S803_XOD 0x300 | ||
142 | #define MC44S803_XOD_S 8 | ||
143 | #define MC44S803_RST 0x10000 | ||
144 | #define MC44S803_RST_S 16 | ||
145 | #define MC44S803_LO_REF 0x1FFF00 | ||
146 | #define MC44S803_LO_REF_S 8 | ||
147 | #define MC44S803_AT 0x200000 | ||
148 | #define MC44S803_AT_S 21 | ||
149 | #define MC44S803_MT 0x400000 | ||
150 | #define MC44S803_MT_S 22 | ||
151 | /* REG_LNAAGC */ | ||
152 | #define MC44S803_G 0x3F0 | ||
153 | #define MC44S803_G_S 4 | ||
154 | #define MC44S803_AT1 0x400 | ||
155 | #define MC44S803_AT1_S 10 | ||
156 | #define MC44S803_AT2 0x800 | ||
157 | #define MC44S803_AT2_S 11 | ||
158 | #define MC44S803_HL_GR_EN 0x8000 | ||
159 | #define MC44S803_HL_GR_EN_S 15 | ||
160 | #define MC44S803_AGC_AN_DIG 0x10000 | ||
161 | #define MC44S803_AGC_AN_DIG_S 16 | ||
162 | #define MC44S803_ATTEN_EN 0x20000 | ||
163 | #define MC44S803_ATTEN_EN_S 17 | ||
164 | #define MC44S803_AGC_READ_EN 0x40000 | ||
165 | #define MC44S803_AGC_READ_EN_S 18 | ||
166 | #define MC44S803_LNA0 0x80000 | ||
167 | #define MC44S803_LNA0_S 19 | ||
168 | #define MC44S803_AGC_SEL 0x100000 | ||
169 | #define MC44S803_AGC_SEL_S 20 | ||
170 | #define MC44S803_AT0 0x200000 | ||
171 | #define MC44S803_AT0_S 21 | ||
172 | #define MC44S803_B 0xC00000 | ||
173 | #define MC44S803_B_S 22 | ||
174 | /* REG_DATAREG */ | ||
175 | #define MC44S803_D 0xF0 | ||
176 | #define MC44S803_D_S 4 | ||
177 | /* REG_REGTEST */ | ||
178 | /* REG_VCOTEST */ | ||
179 | /* REG_LNAGAIN */ | ||
180 | #define MC44S803_IF_PWR 0x700 | ||
181 | #define MC44S803_IF_PWR_S 8 | ||
182 | #define MC44S803_RF_PWR 0x3800 | ||
183 | #define MC44S803_RF_PWR_S 11 | ||
184 | #define MC44S803_LNA_GAIN 0xFC000 | ||
185 | #define MC44S803_LNA_GAIN_S 14 | ||
186 | /* REG_ID */ | ||
187 | #define MC44S803_ID 0x3E00 | ||
188 | #define MC44S803_ID_S 9 | ||
189 | |||
190 | /* Some macros to read/write fields */ | ||
191 | |||
192 | /* First shift, then mask */ | ||
193 | #define MC44S803_REG_SM(_val, _reg) \ | ||
194 | (((_val) << _reg##_S) & (_reg)) | ||
195 | |||
196 | /* First mask, then shift */ | ||
197 | #define MC44S803_REG_MS(_val, _reg) \ | ||
198 | (((_val) & (_reg)) >> _reg##_S) | ||
199 | |||
200 | struct mc44s803_priv { | ||
201 | struct mc44s803_config *cfg; | ||
202 | struct i2c_adapter *i2c; | ||
203 | struct dvb_frontend *fe; | ||
204 | |||
205 | u32 frequency; | ||
206 | }; | ||
207 | |||
208 | #endif | ||
diff --git a/drivers/media/tuners/mt2060.c b/drivers/media/tuners/mt2060.c new file mode 100644 index 000000000000..13381de58a84 --- /dev/null +++ b/drivers/media/tuners/mt2060.c | |||
@@ -0,0 +1,403 @@ | |||
1 | /* | ||
2 | * Driver for Microtune MT2060 "Single chip dual conversion broadband tuner" | ||
3 | * | ||
4 | * Copyright (c) 2006 Olivier DANET <odanet@caramail.com> | ||
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 | /* In that file, frequencies are expressed in kiloHertz to avoid 32 bits overflows */ | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/dvb/frontend.h> | ||
27 | #include <linux/i2c.h> | ||
28 | #include <linux/slab.h> | ||
29 | |||
30 | #include "dvb_frontend.h" | ||
31 | |||
32 | #include "mt2060.h" | ||
33 | #include "mt2060_priv.h" | ||
34 | |||
35 | static int debug; | ||
36 | module_param(debug, int, 0644); | ||
37 | MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); | ||
38 | |||
39 | #define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "MT2060: " args); printk("\n"); }} while (0) | ||
40 | |||
41 | // Reads a single register | ||
42 | static int mt2060_readreg(struct mt2060_priv *priv, u8 reg, u8 *val) | ||
43 | { | ||
44 | struct i2c_msg msg[2] = { | ||
45 | { .addr = priv->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, | ||
46 | { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val, .len = 1 }, | ||
47 | }; | ||
48 | |||
49 | if (i2c_transfer(priv->i2c, msg, 2) != 2) { | ||
50 | printk(KERN_WARNING "mt2060 I2C read failed\n"); | ||
51 | return -EREMOTEIO; | ||
52 | } | ||
53 | return 0; | ||
54 | } | ||
55 | |||
56 | // Writes a single register | ||
57 | static int mt2060_writereg(struct mt2060_priv *priv, u8 reg, u8 val) | ||
58 | { | ||
59 | u8 buf[2] = { reg, val }; | ||
60 | struct i2c_msg msg = { | ||
61 | .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2 | ||
62 | }; | ||
63 | |||
64 | if (i2c_transfer(priv->i2c, &msg, 1) != 1) { | ||
65 | printk(KERN_WARNING "mt2060 I2C write failed\n"); | ||
66 | return -EREMOTEIO; | ||
67 | } | ||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | // Writes a set of consecutive registers | ||
72 | static int mt2060_writeregs(struct mt2060_priv *priv,u8 *buf, u8 len) | ||
73 | { | ||
74 | struct i2c_msg msg = { | ||
75 | .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len | ||
76 | }; | ||
77 | if (i2c_transfer(priv->i2c, &msg, 1) != 1) { | ||
78 | printk(KERN_WARNING "mt2060 I2C write failed (len=%i)\n",(int)len); | ||
79 | return -EREMOTEIO; | ||
80 | } | ||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | // Initialisation sequences | ||
85 | // LNABAND=3, NUM1=0x3C, DIV1=0x74, NUM2=0x1080, DIV2=0x49 | ||
86 | static u8 mt2060_config1[] = { | ||
87 | REG_LO1C1, | ||
88 | 0x3F, 0x74, 0x00, 0x08, 0x93 | ||
89 | }; | ||
90 | |||
91 | // FMCG=2, GP2=0, GP1=0 | ||
92 | static u8 mt2060_config2[] = { | ||
93 | REG_MISC_CTRL, | ||
94 | 0x20, 0x1E, 0x30, 0xff, 0x80, 0xff, 0x00, 0x2c, 0x42 | ||
95 | }; | ||
96 | |||
97 | // VGAG=3, V1CSE=1 | ||
98 | |||
99 | #ifdef MT2060_SPURCHECK | ||
100 | /* The function below calculates the frequency offset between the output frequency if2 | ||
101 | and the closer cross modulation subcarrier between lo1 and lo2 up to the tenth harmonic */ | ||
102 | static int mt2060_spurcalc(u32 lo1,u32 lo2,u32 if2) | ||
103 | { | ||
104 | int I,J; | ||
105 | int dia,diamin,diff; | ||
106 | diamin=1000000; | ||
107 | for (I = 1; I < 10; I++) { | ||
108 | J = ((2*I*lo1)/lo2+1)/2; | ||
109 | diff = I*(int)lo1-J*(int)lo2; | ||
110 | if (diff < 0) diff=-diff; | ||
111 | dia = (diff-(int)if2); | ||
112 | if (dia < 0) dia=-dia; | ||
113 | if (diamin > dia) diamin=dia; | ||
114 | } | ||
115 | return diamin; | ||
116 | } | ||
117 | |||
118 | #define BANDWIDTH 4000 // kHz | ||
119 | |||
120 | /* Calculates the frequency offset to add to avoid spurs. Returns 0 if no offset is needed */ | ||
121 | static int mt2060_spurcheck(u32 lo1,u32 lo2,u32 if2) | ||
122 | { | ||
123 | u32 Spur,Sp1,Sp2; | ||
124 | int I,J; | ||
125 | I=0; | ||
126 | J=1000; | ||
127 | |||
128 | Spur=mt2060_spurcalc(lo1,lo2,if2); | ||
129 | if (Spur < BANDWIDTH) { | ||
130 | /* Potential spurs detected */ | ||
131 | dprintk("Spurs before : f_lo1: %d f_lo2: %d (kHz)", | ||
132 | (int)lo1,(int)lo2); | ||
133 | I=1000; | ||
134 | Sp1 = mt2060_spurcalc(lo1+I,lo2+I,if2); | ||
135 | Sp2 = mt2060_spurcalc(lo1-I,lo2-I,if2); | ||
136 | |||
137 | if (Sp1 < Sp2) { | ||
138 | J=-J; I=-I; Spur=Sp2; | ||
139 | } else | ||
140 | Spur=Sp1; | ||
141 | |||
142 | while (Spur < BANDWIDTH) { | ||
143 | I += J; | ||
144 | Spur = mt2060_spurcalc(lo1+I,lo2+I,if2); | ||
145 | } | ||
146 | dprintk("Spurs after : f_lo1: %d f_lo2: %d (kHz)", | ||
147 | (int)(lo1+I),(int)(lo2+I)); | ||
148 | } | ||
149 | return I; | ||
150 | } | ||
151 | #endif | ||
152 | |||
153 | #define IF2 36150 // IF2 frequency = 36.150 MHz | ||
154 | #define FREF 16000 // Quartz oscillator 16 MHz | ||
155 | |||
156 | static int mt2060_set_params(struct dvb_frontend *fe) | ||
157 | { | ||
158 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
159 | struct mt2060_priv *priv; | ||
160 | int ret=0; | ||
161 | int i=0; | ||
162 | u32 freq; | ||
163 | u8 lnaband; | ||
164 | u32 f_lo1,f_lo2; | ||
165 | u32 div1,num1,div2,num2; | ||
166 | u8 b[8]; | ||
167 | u32 if1; | ||
168 | |||
169 | priv = fe->tuner_priv; | ||
170 | |||
171 | if1 = priv->if1_freq; | ||
172 | b[0] = REG_LO1B1; | ||
173 | b[1] = 0xFF; | ||
174 | |||
175 | if (fe->ops.i2c_gate_ctrl) | ||
176 | fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ | ||
177 | |||
178 | mt2060_writeregs(priv,b,2); | ||
179 | |||
180 | freq = c->frequency / 1000; /* Hz -> kHz */ | ||
181 | |||
182 | f_lo1 = freq + if1 * 1000; | ||
183 | f_lo1 = (f_lo1 / 250) * 250; | ||
184 | f_lo2 = f_lo1 - freq - IF2; | ||
185 | // From the Comtech datasheet, the step used is 50kHz. The tuner chip could be more precise | ||
186 | f_lo2 = ((f_lo2 + 25) / 50) * 50; | ||
187 | priv->frequency = (f_lo1 - f_lo2 - IF2) * 1000, | ||
188 | |||
189 | #ifdef MT2060_SPURCHECK | ||
190 | // LO-related spurs detection and correction | ||
191 | num1 = mt2060_spurcheck(f_lo1,f_lo2,IF2); | ||
192 | f_lo1 += num1; | ||
193 | f_lo2 += num1; | ||
194 | #endif | ||
195 | //Frequency LO1 = 16MHz * (DIV1 + NUM1/64 ) | ||
196 | num1 = f_lo1 / (FREF / 64); | ||
197 | div1 = num1 / 64; | ||
198 | num1 &= 0x3f; | ||
199 | |||
200 | // Frequency LO2 = 16MHz * (DIV2 + NUM2/8192 ) | ||
201 | num2 = f_lo2 * 64 / (FREF / 128); | ||
202 | div2 = num2 / 8192; | ||
203 | num2 &= 0x1fff; | ||
204 | |||
205 | if (freq <= 95000) lnaband = 0xB0; else | ||
206 | if (freq <= 180000) lnaband = 0xA0; else | ||
207 | if (freq <= 260000) lnaband = 0x90; else | ||
208 | if (freq <= 335000) lnaband = 0x80; else | ||
209 | if (freq <= 425000) lnaband = 0x70; else | ||
210 | if (freq <= 480000) lnaband = 0x60; else | ||
211 | if (freq <= 570000) lnaband = 0x50; else | ||
212 | if (freq <= 645000) lnaband = 0x40; else | ||
213 | if (freq <= 730000) lnaband = 0x30; else | ||
214 | if (freq <= 810000) lnaband = 0x20; else lnaband = 0x10; | ||
215 | |||
216 | b[0] = REG_LO1C1; | ||
217 | b[1] = lnaband | ((num1 >>2) & 0x0F); | ||
218 | b[2] = div1; | ||
219 | b[3] = (num2 & 0x0F) | ((num1 & 3) << 4); | ||
220 | b[4] = num2 >> 4; | ||
221 | b[5] = ((num2 >>12) & 1) | (div2 << 1); | ||
222 | |||
223 | dprintk("IF1: %dMHz",(int)if1); | ||
224 | dprintk("PLL freq=%dkHz f_lo1=%dkHz f_lo2=%dkHz",(int)freq,(int)f_lo1,(int)f_lo2); | ||
225 | dprintk("PLL div1=%d num1=%d div2=%d num2=%d",(int)div1,(int)num1,(int)div2,(int)num2); | ||
226 | dprintk("PLL [1..5]: %2x %2x %2x %2x %2x",(int)b[1],(int)b[2],(int)b[3],(int)b[4],(int)b[5]); | ||
227 | |||
228 | mt2060_writeregs(priv,b,6); | ||
229 | |||
230 | //Waits for pll lock or timeout | ||
231 | i = 0; | ||
232 | do { | ||
233 | mt2060_readreg(priv,REG_LO_STATUS,b); | ||
234 | if ((b[0] & 0x88)==0x88) | ||
235 | break; | ||
236 | msleep(4); | ||
237 | i++; | ||
238 | } while (i<10); | ||
239 | |||
240 | if (fe->ops.i2c_gate_ctrl) | ||
241 | fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ | ||
242 | |||
243 | return ret; | ||
244 | } | ||
245 | |||
246 | static void mt2060_calibrate(struct mt2060_priv *priv) | ||
247 | { | ||
248 | u8 b = 0; | ||
249 | int i = 0; | ||
250 | |||
251 | if (mt2060_writeregs(priv,mt2060_config1,sizeof(mt2060_config1))) | ||
252 | return; | ||
253 | if (mt2060_writeregs(priv,mt2060_config2,sizeof(mt2060_config2))) | ||
254 | return; | ||
255 | |||
256 | /* initialize the clock output */ | ||
257 | mt2060_writereg(priv, REG_VGAG, (priv->cfg->clock_out << 6) | 0x30); | ||
258 | |||
259 | do { | ||
260 | b |= (1 << 6); // FM1SS; | ||
261 | mt2060_writereg(priv, REG_LO2C1,b); | ||
262 | msleep(20); | ||
263 | |||
264 | if (i == 0) { | ||
265 | b |= (1 << 7); // FM1CA; | ||
266 | mt2060_writereg(priv, REG_LO2C1,b); | ||
267 | b &= ~(1 << 7); // FM1CA; | ||
268 | msleep(20); | ||
269 | } | ||
270 | |||
271 | b &= ~(1 << 6); // FM1SS | ||
272 | mt2060_writereg(priv, REG_LO2C1,b); | ||
273 | |||
274 | msleep(20); | ||
275 | i++; | ||
276 | } while (i < 9); | ||
277 | |||
278 | i = 0; | ||
279 | while (i++ < 10 && mt2060_readreg(priv, REG_MISC_STAT, &b) == 0 && (b & (1 << 6)) == 0) | ||
280 | msleep(20); | ||
281 | |||
282 | if (i <= 10) { | ||
283 | mt2060_readreg(priv, REG_FM_FREQ, &priv->fmfreq); // now find out, what is fmreq used for :) | ||
284 | dprintk("calibration was successful: %d", (int)priv->fmfreq); | ||
285 | } else | ||
286 | dprintk("FMCAL timed out"); | ||
287 | } | ||
288 | |||
289 | static int mt2060_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
290 | { | ||
291 | struct mt2060_priv *priv = fe->tuner_priv; | ||
292 | *frequency = priv->frequency; | ||
293 | return 0; | ||
294 | } | ||
295 | |||
296 | static int mt2060_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
297 | { | ||
298 | *frequency = IF2 * 1000; | ||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | static int mt2060_init(struct dvb_frontend *fe) | ||
303 | { | ||
304 | struct mt2060_priv *priv = fe->tuner_priv; | ||
305 | int ret; | ||
306 | |||
307 | if (fe->ops.i2c_gate_ctrl) | ||
308 | fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ | ||
309 | |||
310 | ret = mt2060_writereg(priv, REG_VGAG, | ||
311 | (priv->cfg->clock_out << 6) | 0x33); | ||
312 | |||
313 | if (fe->ops.i2c_gate_ctrl) | ||
314 | fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ | ||
315 | |||
316 | return ret; | ||
317 | } | ||
318 | |||
319 | static int mt2060_sleep(struct dvb_frontend *fe) | ||
320 | { | ||
321 | struct mt2060_priv *priv = fe->tuner_priv; | ||
322 | int ret; | ||
323 | |||
324 | if (fe->ops.i2c_gate_ctrl) | ||
325 | fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ | ||
326 | |||
327 | ret = mt2060_writereg(priv, REG_VGAG, | ||
328 | (priv->cfg->clock_out << 6) | 0x30); | ||
329 | |||
330 | if (fe->ops.i2c_gate_ctrl) | ||
331 | fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ | ||
332 | |||
333 | return ret; | ||
334 | } | ||
335 | |||
336 | static int mt2060_release(struct dvb_frontend *fe) | ||
337 | { | ||
338 | kfree(fe->tuner_priv); | ||
339 | fe->tuner_priv = NULL; | ||
340 | return 0; | ||
341 | } | ||
342 | |||
343 | static const struct dvb_tuner_ops mt2060_tuner_ops = { | ||
344 | .info = { | ||
345 | .name = "Microtune MT2060", | ||
346 | .frequency_min = 48000000, | ||
347 | .frequency_max = 860000000, | ||
348 | .frequency_step = 50000, | ||
349 | }, | ||
350 | |||
351 | .release = mt2060_release, | ||
352 | |||
353 | .init = mt2060_init, | ||
354 | .sleep = mt2060_sleep, | ||
355 | |||
356 | .set_params = mt2060_set_params, | ||
357 | .get_frequency = mt2060_get_frequency, | ||
358 | .get_if_frequency = mt2060_get_if_frequency, | ||
359 | }; | ||
360 | |||
361 | /* This functions tries to identify a MT2060 tuner by reading the PART/REV register. This is hasty. */ | ||
362 | struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1) | ||
363 | { | ||
364 | struct mt2060_priv *priv = NULL; | ||
365 | u8 id = 0; | ||
366 | |||
367 | priv = kzalloc(sizeof(struct mt2060_priv), GFP_KERNEL); | ||
368 | if (priv == NULL) | ||
369 | return NULL; | ||
370 | |||
371 | priv->cfg = cfg; | ||
372 | priv->i2c = i2c; | ||
373 | priv->if1_freq = if1; | ||
374 | |||
375 | if (fe->ops.i2c_gate_ctrl) | ||
376 | fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ | ||
377 | |||
378 | if (mt2060_readreg(priv,REG_PART_REV,&id) != 0) { | ||
379 | kfree(priv); | ||
380 | return NULL; | ||
381 | } | ||
382 | |||
383 | if (id != PART_REV) { | ||
384 | kfree(priv); | ||
385 | return NULL; | ||
386 | } | ||
387 | printk(KERN_INFO "MT2060: successfully identified (IF1 = %d)\n", if1); | ||
388 | memcpy(&fe->ops.tuner_ops, &mt2060_tuner_ops, sizeof(struct dvb_tuner_ops)); | ||
389 | |||
390 | fe->tuner_priv = priv; | ||
391 | |||
392 | mt2060_calibrate(priv); | ||
393 | |||
394 | if (fe->ops.i2c_gate_ctrl) | ||
395 | fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ | ||
396 | |||
397 | return fe; | ||
398 | } | ||
399 | EXPORT_SYMBOL(mt2060_attach); | ||
400 | |||
401 | MODULE_AUTHOR("Olivier DANET"); | ||
402 | MODULE_DESCRIPTION("Microtune MT2060 silicon tuner driver"); | ||
403 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/tuners/mt2060.h b/drivers/media/tuners/mt2060.h new file mode 100644 index 000000000000..cb60caffb6b6 --- /dev/null +++ b/drivers/media/tuners/mt2060.h | |||
@@ -0,0 +1,43 @@ | |||
1 | /* | ||
2 | * Driver for Microtune MT2060 "Single chip dual conversion broadband tuner" | ||
3 | * | ||
4 | * Copyright (c) 2006 Olivier DANET <odanet@caramail.com> | ||
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 MT2060_H | ||
23 | #define MT2060_H | ||
24 | |||
25 | struct dvb_frontend; | ||
26 | struct i2c_adapter; | ||
27 | |||
28 | struct mt2060_config { | ||
29 | u8 i2c_address; | ||
30 | u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */ | ||
31 | }; | ||
32 | |||
33 | #if defined(CONFIG_MEDIA_TUNER_MT2060) || (defined(CONFIG_MEDIA_TUNER_MT2060_MODULE) && defined(MODULE)) | ||
34 | extern struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1); | ||
35 | #else | ||
36 | static inline struct dvb_frontend * mt2060_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2060_config *cfg, u16 if1) | ||
37 | { | ||
38 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
39 | return NULL; | ||
40 | } | ||
41 | #endif // CONFIG_MEDIA_TUNER_MT2060 | ||
42 | |||
43 | #endif | ||
diff --git a/drivers/media/tuners/mt2060_priv.h b/drivers/media/tuners/mt2060_priv.h new file mode 100644 index 000000000000..2b60de6c707d --- /dev/null +++ b/drivers/media/tuners/mt2060_priv.h | |||
@@ -0,0 +1,104 @@ | |||
1 | /* | ||
2 | * Driver for Microtune MT2060 "Single chip dual conversion broadband tuner" | ||
3 | * | ||
4 | * Copyright (c) 2006 Olivier DANET <odanet@caramail.com> | ||
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 MT2060_PRIV_H | ||
23 | #define MT2060_PRIV_H | ||
24 | |||
25 | // Uncomment the #define below to enable spurs checking. The results where quite unconvincing. | ||
26 | // #define MT2060_SPURCHECK | ||
27 | |||
28 | /* This driver is based on the information available in the datasheet of the | ||
29 | "Comtech SDVBT-3K6M" tuner ( K1000737843.pdf ) which features the MT2060 register map : | ||
30 | |||
31 | I2C Address : 0x60 | ||
32 | |||
33 | Reg.No | B7 | B6 | B5 | B4 | B3 | B2 | B1 | B0 | ( defaults ) | ||
34 | -------------------------------------------------------------------------------- | ||
35 | 00 | [ PART ] | [ REV ] | R = 0x63 | ||
36 | 01 | [ LNABAND ] | [ NUM1(5:2) ] | RW = 0x3F | ||
37 | 02 | [ DIV1 ] | RW = 0x74 | ||
38 | 03 | FM1CA | FM1SS | [ NUM1(1:0) ] | [ NUM2(3:0) ] | RW = 0x00 | ||
39 | 04 | NUM2(11:4) ] | RW = 0x08 | ||
40 | 05 | [ DIV2 ] |NUM2(12)| RW = 0x93 | ||
41 | 06 | L1LK | [ TAD1 ] | L2LK | [ TAD2 ] | R | ||
42 | 07 | [ FMF ] | R | ||
43 | 08 | ? | FMCAL | ? | ? | ? | ? | ? | TEMP | R | ||
44 | 09 | 0 | 0 | [ FMGC ] | 0 | GP02 | GP01 | 0 | RW = 0x20 | ||
45 | 0A | ?? | ||
46 | 0B | 0 | 0 | 1 | 1 | 0 | 0 | [ VGAG ] | RW = 0x30 | ||
47 | 0C | V1CSE | 1 | 1 | 1 | 1 | 1 | 1 | 1 | RW = 0xFF | ||
48 | 0D | 1 | 0 | [ V1CS ] | RW = 0xB0 | ||
49 | 0E | ?? | ||
50 | 0F | ?? | ||
51 | 10 | ?? | ||
52 | 11 | [ LOTO ] | 0 | 0 | 1 | 0 | RW = 0x42 | ||
53 | |||
54 | PART : Part code : 6 for MT2060 | ||
55 | REV : Revision code : 3 for current revision | ||
56 | LNABAND : Input frequency range : ( See code for details ) | ||
57 | NUM1 / DIV1 / NUM2 / DIV2 : Frequencies programming ( See code for details ) | ||
58 | FM1CA : Calibration Start Bit | ||
59 | FM1SS : Calibration Single Step bit | ||
60 | L1LK : LO1 Lock Detect | ||
61 | TAD1 : Tune Line ADC ( ? ) | ||
62 | L2LK : LO2 Lock Detect | ||
63 | TAD2 : Tune Line ADC ( ? ) | ||
64 | FMF : Estimated first IF Center frequency Offset ( ? ) | ||
65 | FM1CAL : Calibration done bit | ||
66 | TEMP : On chip temperature sensor | ||
67 | FMCG : Mixer 1 Cap Gain ( ? ) | ||
68 | GP01 / GP02 : Programmable digital outputs. Unconnected pins ? | ||
69 | V1CSE : LO1 VCO Automatic Capacitor Select Enable ( ? ) | ||
70 | V1CS : LO1 Capacitor Selection Value ( ? ) | ||
71 | LOTO : LO Timeout ( ? ) | ||
72 | VGAG : Tuner Output gain | ||
73 | */ | ||
74 | |||
75 | #define I2C_ADDRESS 0x60 | ||
76 | |||
77 | #define REG_PART_REV 0 | ||
78 | #define REG_LO1C1 1 | ||
79 | #define REG_LO1C2 2 | ||
80 | #define REG_LO2C1 3 | ||
81 | #define REG_LO2C2 4 | ||
82 | #define REG_LO2C3 5 | ||
83 | #define REG_LO_STATUS 6 | ||
84 | #define REG_FM_FREQ 7 | ||
85 | #define REG_MISC_STAT 8 | ||
86 | #define REG_MISC_CTRL 9 | ||
87 | #define REG_RESERVED_A 0x0A | ||
88 | #define REG_VGAG 0x0B | ||
89 | #define REG_LO1B1 0x0C | ||
90 | #define REG_LO1B2 0x0D | ||
91 | #define REG_LOTO 0x11 | ||
92 | |||
93 | #define PART_REV 0x63 // The current driver works only with PART=6 and REV=3 chips | ||
94 | |||
95 | struct mt2060_priv { | ||
96 | struct mt2060_config *cfg; | ||
97 | struct i2c_adapter *i2c; | ||
98 | |||
99 | u32 frequency; | ||
100 | u16 if1_freq; | ||
101 | u8 fmfreq; | ||
102 | }; | ||
103 | |||
104 | #endif | ||
diff --git a/drivers/media/tuners/mt2063.c b/drivers/media/tuners/mt2063.c new file mode 100644 index 000000000000..0ed9091ff48e --- /dev/null +++ b/drivers/media/tuners/mt2063.c | |||
@@ -0,0 +1,2307 @@ | |||
1 | /* | ||
2 | * Driver for mt2063 Micronas tuner | ||
3 | * | ||
4 | * Copyright (c) 2011 Mauro Carvalho Chehab <mchehab@redhat.com> | ||
5 | * | ||
6 | * This driver came from a driver originally written by: | ||
7 | * Henry Wang <Henry.wang@AzureWave.com> | ||
8 | * Made publicly available by Terratec, at: | ||
9 | * http://linux.terratec.de/files/TERRATEC_H7/20110323_TERRATEC_H7_Linux.tar.gz | ||
10 | * The original driver's license is GPL, as declared with MODULE_LICENSE() | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation under version 2 of the License. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | */ | ||
21 | |||
22 | #include <linux/init.h> | ||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/string.h> | ||
26 | #include <linux/videodev2.h> | ||
27 | |||
28 | #include "mt2063.h" | ||
29 | |||
30 | static unsigned int debug; | ||
31 | module_param(debug, int, 0644); | ||
32 | MODULE_PARM_DESC(debug, "Set Verbosity level"); | ||
33 | |||
34 | #define dprintk(level, fmt, arg...) do { \ | ||
35 | if (debug >= level) \ | ||
36 | printk(KERN_DEBUG "mt2063 %s: " fmt, __func__, ## arg); \ | ||
37 | } while (0) | ||
38 | |||
39 | |||
40 | /* positive error codes used internally */ | ||
41 | |||
42 | /* Info: Unavoidable LO-related spur may be present in the output */ | ||
43 | #define MT2063_SPUR_PRESENT_ERR (0x00800000) | ||
44 | |||
45 | /* Info: Mask of bits used for # of LO-related spurs that were avoided during tuning */ | ||
46 | #define MT2063_SPUR_CNT_MASK (0x001f0000) | ||
47 | #define MT2063_SPUR_SHIFT (16) | ||
48 | |||
49 | /* Info: Upconverter frequency is out of range (may be reason for MT_UPC_UNLOCK) */ | ||
50 | #define MT2063_UPC_RANGE (0x04000000) | ||
51 | |||
52 | /* Info: Downconverter frequency is out of range (may be reason for MT_DPC_UNLOCK) */ | ||
53 | #define MT2063_DNC_RANGE (0x08000000) | ||
54 | |||
55 | /* | ||
56 | * Constant defining the version of the following structure | ||
57 | * and therefore the API for this code. | ||
58 | * | ||
59 | * When compiling the tuner driver, the preprocessor will | ||
60 | * check against this version number to make sure that | ||
61 | * it matches the version that the tuner driver knows about. | ||
62 | */ | ||
63 | |||
64 | /* DECT Frequency Avoidance */ | ||
65 | #define MT2063_DECT_AVOID_US_FREQS 0x00000001 | ||
66 | |||
67 | #define MT2063_DECT_AVOID_EURO_FREQS 0x00000002 | ||
68 | |||
69 | #define MT2063_EXCLUDE_US_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_US_FREQS) != 0) | ||
70 | |||
71 | #define MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(s) (((s) & MT2063_DECT_AVOID_EURO_FREQS) != 0) | ||
72 | |||
73 | enum MT2063_DECT_Avoid_Type { | ||
74 | MT2063_NO_DECT_AVOIDANCE = 0, /* Do not create DECT exclusion zones. */ | ||
75 | MT2063_AVOID_US_DECT = MT2063_DECT_AVOID_US_FREQS, /* Avoid US DECT frequencies. */ | ||
76 | MT2063_AVOID_EURO_DECT = MT2063_DECT_AVOID_EURO_FREQS, /* Avoid European DECT frequencies. */ | ||
77 | MT2063_AVOID_BOTH /* Avoid both regions. Not typically used. */ | ||
78 | }; | ||
79 | |||
80 | #define MT2063_MAX_ZONES 48 | ||
81 | |||
82 | struct MT2063_ExclZone_t { | ||
83 | u32 min_; | ||
84 | u32 max_; | ||
85 | struct MT2063_ExclZone_t *next_; | ||
86 | }; | ||
87 | |||
88 | /* | ||
89 | * Structure of data needed for Spur Avoidance | ||
90 | */ | ||
91 | struct MT2063_AvoidSpursData_t { | ||
92 | u32 f_ref; | ||
93 | u32 f_in; | ||
94 | u32 f_LO1; | ||
95 | u32 f_if1_Center; | ||
96 | u32 f_if1_Request; | ||
97 | u32 f_if1_bw; | ||
98 | u32 f_LO2; | ||
99 | u32 f_out; | ||
100 | u32 f_out_bw; | ||
101 | u32 f_LO1_Step; | ||
102 | u32 f_LO2_Step; | ||
103 | u32 f_LO1_FracN_Avoid; | ||
104 | u32 f_LO2_FracN_Avoid; | ||
105 | u32 f_zif_bw; | ||
106 | u32 f_min_LO_Separation; | ||
107 | u32 maxH1; | ||
108 | u32 maxH2; | ||
109 | enum MT2063_DECT_Avoid_Type avoidDECT; | ||
110 | u32 bSpurPresent; | ||
111 | u32 bSpurAvoided; | ||
112 | u32 nSpursFound; | ||
113 | u32 nZones; | ||
114 | struct MT2063_ExclZone_t *freeZones; | ||
115 | struct MT2063_ExclZone_t *usedZones; | ||
116 | struct MT2063_ExclZone_t MT2063_ExclZones[MT2063_MAX_ZONES]; | ||
117 | }; | ||
118 | |||
119 | /* | ||
120 | * Parameter for function MT2063_SetPowerMask that specifies the power down | ||
121 | * of various sections of the MT2063. | ||
122 | */ | ||
123 | enum MT2063_Mask_Bits { | ||
124 | MT2063_REG_SD = 0x0040, /* Shutdown regulator */ | ||
125 | MT2063_SRO_SD = 0x0020, /* Shutdown SRO */ | ||
126 | MT2063_AFC_SD = 0x0010, /* Shutdown AFC A/D */ | ||
127 | MT2063_PD_SD = 0x0002, /* Enable power detector shutdown */ | ||
128 | MT2063_PDADC_SD = 0x0001, /* Enable power detector A/D shutdown */ | ||
129 | MT2063_VCO_SD = 0x8000, /* Enable VCO shutdown */ | ||
130 | MT2063_LTX_SD = 0x4000, /* Enable LTX shutdown */ | ||
131 | MT2063_LT1_SD = 0x2000, /* Enable LT1 shutdown */ | ||
132 | MT2063_LNA_SD = 0x1000, /* Enable LNA shutdown */ | ||
133 | MT2063_UPC_SD = 0x0800, /* Enable upconverter shutdown */ | ||
134 | MT2063_DNC_SD = 0x0400, /* Enable downconverter shutdown */ | ||
135 | MT2063_VGA_SD = 0x0200, /* Enable VGA shutdown */ | ||
136 | MT2063_AMP_SD = 0x0100, /* Enable AMP shutdown */ | ||
137 | MT2063_ALL_SD = 0xFF73, /* All shutdown bits for this tuner */ | ||
138 | MT2063_NONE_SD = 0x0000 /* No shutdown bits */ | ||
139 | }; | ||
140 | |||
141 | /* | ||
142 | * Possible values for MT2063_DNC_OUTPUT | ||
143 | */ | ||
144 | enum MT2063_DNC_Output_Enable { | ||
145 | MT2063_DNC_NONE = 0, | ||
146 | MT2063_DNC_1, | ||
147 | MT2063_DNC_2, | ||
148 | MT2063_DNC_BOTH | ||
149 | }; | ||
150 | |||
151 | /* | ||
152 | * Two-wire serial bus subaddresses of the tuner registers. | ||
153 | * Also known as the tuner's register addresses. | ||
154 | */ | ||
155 | enum MT2063_Register_Offsets { | ||
156 | MT2063_REG_PART_REV = 0, /* 0x00: Part/Rev Code */ | ||
157 | MT2063_REG_LO1CQ_1, /* 0x01: LO1C Queued Byte 1 */ | ||
158 | MT2063_REG_LO1CQ_2, /* 0x02: LO1C Queued Byte 2 */ | ||
159 | MT2063_REG_LO2CQ_1, /* 0x03: LO2C Queued Byte 1 */ | ||
160 | MT2063_REG_LO2CQ_2, /* 0x04: LO2C Queued Byte 2 */ | ||
161 | MT2063_REG_LO2CQ_3, /* 0x05: LO2C Queued Byte 3 */ | ||
162 | MT2063_REG_RSVD_06, /* 0x06: Reserved */ | ||
163 | MT2063_REG_LO_STATUS, /* 0x07: LO Status */ | ||
164 | MT2063_REG_FIFFC, /* 0x08: FIFF Center */ | ||
165 | MT2063_REG_CLEARTUNE, /* 0x09: ClearTune Filter */ | ||
166 | MT2063_REG_ADC_OUT, /* 0x0A: ADC_OUT */ | ||
167 | MT2063_REG_LO1C_1, /* 0x0B: LO1C Byte 1 */ | ||
168 | MT2063_REG_LO1C_2, /* 0x0C: LO1C Byte 2 */ | ||
169 | MT2063_REG_LO2C_1, /* 0x0D: LO2C Byte 1 */ | ||
170 | MT2063_REG_LO2C_2, /* 0x0E: LO2C Byte 2 */ | ||
171 | MT2063_REG_LO2C_3, /* 0x0F: LO2C Byte 3 */ | ||
172 | MT2063_REG_RSVD_10, /* 0x10: Reserved */ | ||
173 | MT2063_REG_PWR_1, /* 0x11: PWR Byte 1 */ | ||
174 | MT2063_REG_PWR_2, /* 0x12: PWR Byte 2 */ | ||
175 | MT2063_REG_TEMP_STATUS, /* 0x13: Temp Status */ | ||
176 | MT2063_REG_XO_STATUS, /* 0x14: Crystal Status */ | ||
177 | MT2063_REG_RF_STATUS, /* 0x15: RF Attn Status */ | ||
178 | MT2063_REG_FIF_STATUS, /* 0x16: FIF Attn Status */ | ||
179 | MT2063_REG_LNA_OV, /* 0x17: LNA Attn Override */ | ||
180 | MT2063_REG_RF_OV, /* 0x18: RF Attn Override */ | ||
181 | MT2063_REG_FIF_OV, /* 0x19: FIF Attn Override */ | ||
182 | MT2063_REG_LNA_TGT, /* 0x1A: Reserved */ | ||
183 | MT2063_REG_PD1_TGT, /* 0x1B: Pwr Det 1 Target */ | ||
184 | MT2063_REG_PD2_TGT, /* 0x1C: Pwr Det 2 Target */ | ||
185 | MT2063_REG_RSVD_1D, /* 0x1D: Reserved */ | ||
186 | MT2063_REG_RSVD_1E, /* 0x1E: Reserved */ | ||
187 | MT2063_REG_RSVD_1F, /* 0x1F: Reserved */ | ||
188 | MT2063_REG_RSVD_20, /* 0x20: Reserved */ | ||
189 | MT2063_REG_BYP_CTRL, /* 0x21: Bypass Control */ | ||
190 | MT2063_REG_RSVD_22, /* 0x22: Reserved */ | ||
191 | MT2063_REG_RSVD_23, /* 0x23: Reserved */ | ||
192 | MT2063_REG_RSVD_24, /* 0x24: Reserved */ | ||
193 | MT2063_REG_RSVD_25, /* 0x25: Reserved */ | ||
194 | MT2063_REG_RSVD_26, /* 0x26: Reserved */ | ||
195 | MT2063_REG_RSVD_27, /* 0x27: Reserved */ | ||
196 | MT2063_REG_FIFF_CTRL, /* 0x28: FIFF Control */ | ||
197 | MT2063_REG_FIFF_OFFSET, /* 0x29: FIFF Offset */ | ||
198 | MT2063_REG_CTUNE_CTRL, /* 0x2A: Reserved */ | ||
199 | MT2063_REG_CTUNE_OV, /* 0x2B: Reserved */ | ||
200 | MT2063_REG_CTRL_2C, /* 0x2C: Reserved */ | ||
201 | MT2063_REG_FIFF_CTRL2, /* 0x2D: Fiff Control */ | ||
202 | MT2063_REG_RSVD_2E, /* 0x2E: Reserved */ | ||
203 | MT2063_REG_DNC_GAIN, /* 0x2F: DNC Control */ | ||
204 | MT2063_REG_VGA_GAIN, /* 0x30: VGA Gain Ctrl */ | ||
205 | MT2063_REG_RSVD_31, /* 0x31: Reserved */ | ||
206 | MT2063_REG_TEMP_SEL, /* 0x32: Temperature Selection */ | ||
207 | MT2063_REG_RSVD_33, /* 0x33: Reserved */ | ||
208 | MT2063_REG_RSVD_34, /* 0x34: Reserved */ | ||
209 | MT2063_REG_RSVD_35, /* 0x35: Reserved */ | ||
210 | MT2063_REG_RSVD_36, /* 0x36: Reserved */ | ||
211 | MT2063_REG_RSVD_37, /* 0x37: Reserved */ | ||
212 | MT2063_REG_RSVD_38, /* 0x38: Reserved */ | ||
213 | MT2063_REG_RSVD_39, /* 0x39: Reserved */ | ||
214 | MT2063_REG_RSVD_3A, /* 0x3A: Reserved */ | ||
215 | MT2063_REG_RSVD_3B, /* 0x3B: Reserved */ | ||
216 | MT2063_REG_RSVD_3C, /* 0x3C: Reserved */ | ||
217 | MT2063_REG_END_REGS | ||
218 | }; | ||
219 | |||
220 | struct mt2063_state { | ||
221 | struct i2c_adapter *i2c; | ||
222 | |||
223 | bool init; | ||
224 | |||
225 | const struct mt2063_config *config; | ||
226 | struct dvb_tuner_ops ops; | ||
227 | struct dvb_frontend *frontend; | ||
228 | struct tuner_state status; | ||
229 | |||
230 | u32 frequency; | ||
231 | u32 srate; | ||
232 | u32 bandwidth; | ||
233 | u32 reference; | ||
234 | |||
235 | u32 tuner_id; | ||
236 | struct MT2063_AvoidSpursData_t AS_Data; | ||
237 | u32 f_IF1_actual; | ||
238 | u32 rcvr_mode; | ||
239 | u32 ctfilt_sw; | ||
240 | u32 CTFiltMax[31]; | ||
241 | u32 num_regs; | ||
242 | u8 reg[MT2063_REG_END_REGS]; | ||
243 | }; | ||
244 | |||
245 | /* | ||
246 | * mt2063_write - Write data into the I2C bus | ||
247 | */ | ||
248 | static u32 mt2063_write(struct mt2063_state *state, u8 reg, u8 *data, u32 len) | ||
249 | { | ||
250 | struct dvb_frontend *fe = state->frontend; | ||
251 | int ret; | ||
252 | u8 buf[60]; | ||
253 | struct i2c_msg msg = { | ||
254 | .addr = state->config->tuner_address, | ||
255 | .flags = 0, | ||
256 | .buf = buf, | ||
257 | .len = len + 1 | ||
258 | }; | ||
259 | |||
260 | dprintk(2, "\n"); | ||
261 | |||
262 | msg.buf[0] = reg; | ||
263 | memcpy(msg.buf + 1, data, len); | ||
264 | |||
265 | if (fe->ops.i2c_gate_ctrl) | ||
266 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
267 | ret = i2c_transfer(state->i2c, &msg, 1); | ||
268 | if (fe->ops.i2c_gate_ctrl) | ||
269 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
270 | |||
271 | if (ret < 0) | ||
272 | printk(KERN_ERR "%s error ret=%d\n", __func__, ret); | ||
273 | |||
274 | return ret; | ||
275 | } | ||
276 | |||
277 | /* | ||
278 | * mt2063_write - Write register data into the I2C bus, caching the value | ||
279 | */ | ||
280 | static u32 mt2063_setreg(struct mt2063_state *state, u8 reg, u8 val) | ||
281 | { | ||
282 | u32 status; | ||
283 | |||
284 | dprintk(2, "\n"); | ||
285 | |||
286 | if (reg >= MT2063_REG_END_REGS) | ||
287 | return -ERANGE; | ||
288 | |||
289 | status = mt2063_write(state, reg, &val, 1); | ||
290 | if (status < 0) | ||
291 | return status; | ||
292 | |||
293 | state->reg[reg] = val; | ||
294 | |||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | /* | ||
299 | * mt2063_read - Read data from the I2C bus | ||
300 | */ | ||
301 | static u32 mt2063_read(struct mt2063_state *state, | ||
302 | u8 subAddress, u8 *pData, u32 cnt) | ||
303 | { | ||
304 | u32 status = 0; /* Status to be returned */ | ||
305 | struct dvb_frontend *fe = state->frontend; | ||
306 | u32 i = 0; | ||
307 | |||
308 | dprintk(2, "addr 0x%02x, cnt %d\n", subAddress, cnt); | ||
309 | |||
310 | if (fe->ops.i2c_gate_ctrl) | ||
311 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
312 | |||
313 | for (i = 0; i < cnt; i++) { | ||
314 | u8 b0[] = { subAddress + i }; | ||
315 | struct i2c_msg msg[] = { | ||
316 | { | ||
317 | .addr = state->config->tuner_address, | ||
318 | .flags = 0, | ||
319 | .buf = b0, | ||
320 | .len = 1 | ||
321 | }, { | ||
322 | .addr = state->config->tuner_address, | ||
323 | .flags = I2C_M_RD, | ||
324 | .buf = pData + i, | ||
325 | .len = 1 | ||
326 | } | ||
327 | }; | ||
328 | |||
329 | status = i2c_transfer(state->i2c, msg, 2); | ||
330 | dprintk(2, "addr 0x%02x, ret = %d, val = 0x%02x\n", | ||
331 | subAddress + i, status, *(pData + i)); | ||
332 | if (status < 0) | ||
333 | break; | ||
334 | } | ||
335 | if (fe->ops.i2c_gate_ctrl) | ||
336 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
337 | |||
338 | if (status < 0) | ||
339 | printk(KERN_ERR "Can't read from address 0x%02x,\n", | ||
340 | subAddress + i); | ||
341 | |||
342 | return status; | ||
343 | } | ||
344 | |||
345 | /* | ||
346 | * FIXME: Is this really needed? | ||
347 | */ | ||
348 | static int MT2063_Sleep(struct dvb_frontend *fe) | ||
349 | { | ||
350 | /* | ||
351 | * ToDo: Add code here to implement a OS blocking | ||
352 | */ | ||
353 | msleep(100); | ||
354 | |||
355 | return 0; | ||
356 | } | ||
357 | |||
358 | /* | ||
359 | * Microtune spur avoidance | ||
360 | */ | ||
361 | |||
362 | /* Implement ceiling, floor functions. */ | ||
363 | #define ceil(n, d) (((n) < 0) ? (-((-(n))/(d))) : (n)/(d) + ((n)%(d) != 0)) | ||
364 | #define floor(n, d) (((n) < 0) ? (-((-(n))/(d))) - ((n)%(d) != 0) : (n)/(d)) | ||
365 | |||
366 | struct MT2063_FIFZone_t { | ||
367 | s32 min_; | ||
368 | s32 max_; | ||
369 | }; | ||
370 | |||
371 | static struct MT2063_ExclZone_t *InsertNode(struct MT2063_AvoidSpursData_t | ||
372 | *pAS_Info, | ||
373 | struct MT2063_ExclZone_t *pPrevNode) | ||
374 | { | ||
375 | struct MT2063_ExclZone_t *pNode; | ||
376 | |||
377 | dprintk(2, "\n"); | ||
378 | |||
379 | /* Check for a node in the free list */ | ||
380 | if (pAS_Info->freeZones != NULL) { | ||
381 | /* Use one from the free list */ | ||
382 | pNode = pAS_Info->freeZones; | ||
383 | pAS_Info->freeZones = pNode->next_; | ||
384 | } else { | ||
385 | /* Grab a node from the array */ | ||
386 | pNode = &pAS_Info->MT2063_ExclZones[pAS_Info->nZones]; | ||
387 | } | ||
388 | |||
389 | if (pPrevNode != NULL) { | ||
390 | pNode->next_ = pPrevNode->next_; | ||
391 | pPrevNode->next_ = pNode; | ||
392 | } else { /* insert at the beginning of the list */ | ||
393 | |||
394 | pNode->next_ = pAS_Info->usedZones; | ||
395 | pAS_Info->usedZones = pNode; | ||
396 | } | ||
397 | |||
398 | pAS_Info->nZones++; | ||
399 | return pNode; | ||
400 | } | ||
401 | |||
402 | static struct MT2063_ExclZone_t *RemoveNode(struct MT2063_AvoidSpursData_t | ||
403 | *pAS_Info, | ||
404 | struct MT2063_ExclZone_t *pPrevNode, | ||
405 | struct MT2063_ExclZone_t | ||
406 | *pNodeToRemove) | ||
407 | { | ||
408 | struct MT2063_ExclZone_t *pNext = pNodeToRemove->next_; | ||
409 | |||
410 | dprintk(2, "\n"); | ||
411 | |||
412 | /* Make previous node point to the subsequent node */ | ||
413 | if (pPrevNode != NULL) | ||
414 | pPrevNode->next_ = pNext; | ||
415 | |||
416 | /* Add pNodeToRemove to the beginning of the freeZones */ | ||
417 | pNodeToRemove->next_ = pAS_Info->freeZones; | ||
418 | pAS_Info->freeZones = pNodeToRemove; | ||
419 | |||
420 | /* Decrement node count */ | ||
421 | pAS_Info->nZones--; | ||
422 | |||
423 | return pNext; | ||
424 | } | ||
425 | |||
426 | /* | ||
427 | * MT_AddExclZone() | ||
428 | * | ||
429 | * Add (and merge) an exclusion zone into the list. | ||
430 | * If the range (f_min, f_max) is totally outside the | ||
431 | * 1st IF BW, ignore the entry. | ||
432 | * If the range (f_min, f_max) is negative, ignore the entry. | ||
433 | */ | ||
434 | static void MT2063_AddExclZone(struct MT2063_AvoidSpursData_t *pAS_Info, | ||
435 | u32 f_min, u32 f_max) | ||
436 | { | ||
437 | struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones; | ||
438 | struct MT2063_ExclZone_t *pPrev = NULL; | ||
439 | struct MT2063_ExclZone_t *pNext = NULL; | ||
440 | |||
441 | dprintk(2, "\n"); | ||
442 | |||
443 | /* Check to see if this overlaps the 1st IF filter */ | ||
444 | if ((f_max > (pAS_Info->f_if1_Center - (pAS_Info->f_if1_bw / 2))) | ||
445 | && (f_min < (pAS_Info->f_if1_Center + (pAS_Info->f_if1_bw / 2))) | ||
446 | && (f_min < f_max)) { | ||
447 | /* | ||
448 | * 1 2 3 4 5 6 | ||
449 | * | ||
450 | * New entry: |---| |--| |--| |-| |---| |--| | ||
451 | * or or or or or | ||
452 | * Existing: |--| |--| |--| |---| |-| |--| | ||
453 | */ | ||
454 | |||
455 | /* Check for our place in the list */ | ||
456 | while ((pNode != NULL) && (pNode->max_ < f_min)) { | ||
457 | pPrev = pNode; | ||
458 | pNode = pNode->next_; | ||
459 | } | ||
460 | |||
461 | if ((pNode != NULL) && (pNode->min_ < f_max)) { | ||
462 | /* Combine me with pNode */ | ||
463 | if (f_min < pNode->min_) | ||
464 | pNode->min_ = f_min; | ||
465 | if (f_max > pNode->max_) | ||
466 | pNode->max_ = f_max; | ||
467 | } else { | ||
468 | pNode = InsertNode(pAS_Info, pPrev); | ||
469 | pNode->min_ = f_min; | ||
470 | pNode->max_ = f_max; | ||
471 | } | ||
472 | |||
473 | /* Look for merging possibilities */ | ||
474 | pNext = pNode->next_; | ||
475 | while ((pNext != NULL) && (pNext->min_ < pNode->max_)) { | ||
476 | if (pNext->max_ > pNode->max_) | ||
477 | pNode->max_ = pNext->max_; | ||
478 | /* Remove pNext, return ptr to pNext->next */ | ||
479 | pNext = RemoveNode(pAS_Info, pNode, pNext); | ||
480 | } | ||
481 | } | ||
482 | } | ||
483 | |||
484 | /* | ||
485 | * Reset all exclusion zones. | ||
486 | * Add zones to protect the PLL FracN regions near zero | ||
487 | */ | ||
488 | static void MT2063_ResetExclZones(struct MT2063_AvoidSpursData_t *pAS_Info) | ||
489 | { | ||
490 | u32 center; | ||
491 | |||
492 | dprintk(2, "\n"); | ||
493 | |||
494 | pAS_Info->nZones = 0; /* this clears the used list */ | ||
495 | pAS_Info->usedZones = NULL; /* reset ptr */ | ||
496 | pAS_Info->freeZones = NULL; /* reset ptr */ | ||
497 | |||
498 | center = | ||
499 | pAS_Info->f_ref * | ||
500 | ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 + | ||
501 | pAS_Info->f_in) / pAS_Info->f_ref) - pAS_Info->f_in; | ||
502 | while (center < | ||
503 | pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 + | ||
504 | pAS_Info->f_LO1_FracN_Avoid) { | ||
505 | /* Exclude LO1 FracN */ | ||
506 | MT2063_AddExclZone(pAS_Info, | ||
507 | center - pAS_Info->f_LO1_FracN_Avoid, | ||
508 | center - 1); | ||
509 | MT2063_AddExclZone(pAS_Info, center + 1, | ||
510 | center + pAS_Info->f_LO1_FracN_Avoid); | ||
511 | center += pAS_Info->f_ref; | ||
512 | } | ||
513 | |||
514 | center = | ||
515 | pAS_Info->f_ref * | ||
516 | ((pAS_Info->f_if1_Center - pAS_Info->f_if1_bw / 2 - | ||
517 | pAS_Info->f_out) / pAS_Info->f_ref) + pAS_Info->f_out; | ||
518 | while (center < | ||
519 | pAS_Info->f_if1_Center + pAS_Info->f_if1_bw / 2 + | ||
520 | pAS_Info->f_LO2_FracN_Avoid) { | ||
521 | /* Exclude LO2 FracN */ | ||
522 | MT2063_AddExclZone(pAS_Info, | ||
523 | center - pAS_Info->f_LO2_FracN_Avoid, | ||
524 | center - 1); | ||
525 | MT2063_AddExclZone(pAS_Info, center + 1, | ||
526 | center + pAS_Info->f_LO2_FracN_Avoid); | ||
527 | center += pAS_Info->f_ref; | ||
528 | } | ||
529 | |||
530 | if (MT2063_EXCLUDE_US_DECT_FREQUENCIES(pAS_Info->avoidDECT)) { | ||
531 | /* Exclude LO1 values that conflict with DECT channels */ | ||
532 | MT2063_AddExclZone(pAS_Info, 1920836000 - pAS_Info->f_in, 1922236000 - pAS_Info->f_in); /* Ctr = 1921.536 */ | ||
533 | MT2063_AddExclZone(pAS_Info, 1922564000 - pAS_Info->f_in, 1923964000 - pAS_Info->f_in); /* Ctr = 1923.264 */ | ||
534 | MT2063_AddExclZone(pAS_Info, 1924292000 - pAS_Info->f_in, 1925692000 - pAS_Info->f_in); /* Ctr = 1924.992 */ | ||
535 | MT2063_AddExclZone(pAS_Info, 1926020000 - pAS_Info->f_in, 1927420000 - pAS_Info->f_in); /* Ctr = 1926.720 */ | ||
536 | MT2063_AddExclZone(pAS_Info, 1927748000 - pAS_Info->f_in, 1929148000 - pAS_Info->f_in); /* Ctr = 1928.448 */ | ||
537 | } | ||
538 | |||
539 | if (MT2063_EXCLUDE_EURO_DECT_FREQUENCIES(pAS_Info->avoidDECT)) { | ||
540 | MT2063_AddExclZone(pAS_Info, 1896644000 - pAS_Info->f_in, 1898044000 - pAS_Info->f_in); /* Ctr = 1897.344 */ | ||
541 | MT2063_AddExclZone(pAS_Info, 1894916000 - pAS_Info->f_in, 1896316000 - pAS_Info->f_in); /* Ctr = 1895.616 */ | ||
542 | MT2063_AddExclZone(pAS_Info, 1893188000 - pAS_Info->f_in, 1894588000 - pAS_Info->f_in); /* Ctr = 1893.888 */ | ||
543 | MT2063_AddExclZone(pAS_Info, 1891460000 - pAS_Info->f_in, 1892860000 - pAS_Info->f_in); /* Ctr = 1892.16 */ | ||
544 | MT2063_AddExclZone(pAS_Info, 1889732000 - pAS_Info->f_in, 1891132000 - pAS_Info->f_in); /* Ctr = 1890.432 */ | ||
545 | MT2063_AddExclZone(pAS_Info, 1888004000 - pAS_Info->f_in, 1889404000 - pAS_Info->f_in); /* Ctr = 1888.704 */ | ||
546 | MT2063_AddExclZone(pAS_Info, 1886276000 - pAS_Info->f_in, 1887676000 - pAS_Info->f_in); /* Ctr = 1886.976 */ | ||
547 | MT2063_AddExclZone(pAS_Info, 1884548000 - pAS_Info->f_in, 1885948000 - pAS_Info->f_in); /* Ctr = 1885.248 */ | ||
548 | MT2063_AddExclZone(pAS_Info, 1882820000 - pAS_Info->f_in, 1884220000 - pAS_Info->f_in); /* Ctr = 1883.52 */ | ||
549 | MT2063_AddExclZone(pAS_Info, 1881092000 - pAS_Info->f_in, 1882492000 - pAS_Info->f_in); /* Ctr = 1881.792 */ | ||
550 | } | ||
551 | } | ||
552 | |||
553 | /* | ||
554 | * MT_ChooseFirstIF - Choose the best available 1st IF | ||
555 | * If f_Desired is not excluded, choose that first. | ||
556 | * Otherwise, return the value closest to f_Center that is | ||
557 | * not excluded | ||
558 | */ | ||
559 | static u32 MT2063_ChooseFirstIF(struct MT2063_AvoidSpursData_t *pAS_Info) | ||
560 | { | ||
561 | /* | ||
562 | * Update "f_Desired" to be the nearest "combinational-multiple" of | ||
563 | * "f_LO1_Step". | ||
564 | * The resulting number, F_LO1 must be a multiple of f_LO1_Step. | ||
565 | * And F_LO1 is the arithmetic sum of f_in + f_Center. | ||
566 | * Neither f_in, nor f_Center must be a multiple of f_LO1_Step. | ||
567 | * However, the sum must be. | ||
568 | */ | ||
569 | const u32 f_Desired = | ||
570 | pAS_Info->f_LO1_Step * | ||
571 | ((pAS_Info->f_if1_Request + pAS_Info->f_in + | ||
572 | pAS_Info->f_LO1_Step / 2) / pAS_Info->f_LO1_Step) - | ||
573 | pAS_Info->f_in; | ||
574 | const u32 f_Step = | ||
575 | (pAS_Info->f_LO1_Step > | ||
576 | pAS_Info->f_LO2_Step) ? pAS_Info->f_LO1_Step : pAS_Info-> | ||
577 | f_LO2_Step; | ||
578 | u32 f_Center; | ||
579 | s32 i; | ||
580 | s32 j = 0; | ||
581 | u32 bDesiredExcluded = 0; | ||
582 | u32 bZeroExcluded = 0; | ||
583 | s32 tmpMin, tmpMax; | ||
584 | s32 bestDiff; | ||
585 | struct MT2063_ExclZone_t *pNode = pAS_Info->usedZones; | ||
586 | struct MT2063_FIFZone_t zones[MT2063_MAX_ZONES]; | ||
587 | |||
588 | dprintk(2, "\n"); | ||
589 | |||
590 | if (pAS_Info->nZones == 0) | ||
591 | return f_Desired; | ||
592 | |||
593 | /* | ||
594 | * f_Center needs to be an integer multiple of f_Step away | ||
595 | * from f_Desired | ||
596 | */ | ||
597 | if (pAS_Info->f_if1_Center > f_Desired) | ||
598 | f_Center = | ||
599 | f_Desired + | ||
600 | f_Step * | ||
601 | ((pAS_Info->f_if1_Center - f_Desired + | ||
602 | f_Step / 2) / f_Step); | ||
603 | else | ||
604 | f_Center = | ||
605 | f_Desired - | ||
606 | f_Step * | ||
607 | ((f_Desired - pAS_Info->f_if1_Center + | ||
608 | f_Step / 2) / f_Step); | ||
609 | |||
610 | /* | ||
611 | * Take MT_ExclZones, center around f_Center and change the | ||
612 | * resolution to f_Step | ||
613 | */ | ||
614 | while (pNode != NULL) { | ||
615 | /* floor function */ | ||
616 | tmpMin = | ||
617 | floor((s32) (pNode->min_ - f_Center), (s32) f_Step); | ||
618 | |||
619 | /* ceil function */ | ||
620 | tmpMax = | ||
621 | ceil((s32) (pNode->max_ - f_Center), (s32) f_Step); | ||
622 | |||
623 | if ((pNode->min_ < f_Desired) && (pNode->max_ > f_Desired)) | ||
624 | bDesiredExcluded = 1; | ||
625 | |||
626 | if ((tmpMin < 0) && (tmpMax > 0)) | ||
627 | bZeroExcluded = 1; | ||
628 | |||
629 | /* See if this zone overlaps the previous */ | ||
630 | if ((j > 0) && (tmpMin < zones[j - 1].max_)) | ||
631 | zones[j - 1].max_ = tmpMax; | ||
632 | else { | ||
633 | /* Add new zone */ | ||
634 | zones[j].min_ = tmpMin; | ||
635 | zones[j].max_ = tmpMax; | ||
636 | j++; | ||
637 | } | ||
638 | pNode = pNode->next_; | ||
639 | } | ||
640 | |||
641 | /* | ||
642 | * If the desired is okay, return with it | ||
643 | */ | ||
644 | if (bDesiredExcluded == 0) | ||
645 | return f_Desired; | ||
646 | |||
647 | /* | ||
648 | * If the desired is excluded and the center is okay, return with it | ||
649 | */ | ||
650 | if (bZeroExcluded == 0) | ||
651 | return f_Center; | ||
652 | |||
653 | /* Find the value closest to 0 (f_Center) */ | ||
654 | bestDiff = zones[0].min_; | ||
655 | for (i = 0; i < j; i++) { | ||
656 | if (abs(zones[i].min_) < abs(bestDiff)) | ||
657 | bestDiff = zones[i].min_; | ||
658 | if (abs(zones[i].max_) < abs(bestDiff)) | ||
659 | bestDiff = zones[i].max_; | ||
660 | } | ||
661 | |||
662 | if (bestDiff < 0) | ||
663 | return f_Center - ((u32) (-bestDiff) * f_Step); | ||
664 | |||
665 | return f_Center + (bestDiff * f_Step); | ||
666 | } | ||
667 | |||
668 | /** | ||
669 | * gcd() - Uses Euclid's algorithm | ||
670 | * | ||
671 | * @u, @v: Unsigned values whose GCD is desired. | ||
672 | * | ||
673 | * Returns THE greatest common divisor of u and v, if either value is 0, | ||
674 | * the other value is returned as the result. | ||
675 | */ | ||
676 | static u32 MT2063_gcd(u32 u, u32 v) | ||
677 | { | ||
678 | u32 r; | ||
679 | |||
680 | while (v != 0) { | ||
681 | r = u % v; | ||
682 | u = v; | ||
683 | v = r; | ||
684 | } | ||
685 | |||
686 | return u; | ||
687 | } | ||
688 | |||
689 | /** | ||
690 | * IsSpurInBand() - Checks to see if a spur will be present within the IF's | ||
691 | * bandwidth. (fIFOut +/- fIFBW, -fIFOut +/- fIFBW) | ||
692 | * | ||
693 | * ma mb mc md | ||
694 | * <--+-+-+-------------------+-------------------+-+-+--> | ||
695 | * | ^ 0 ^ | | ||
696 | * ^ b=-fIFOut+fIFBW/2 -b=+fIFOut-fIFBW/2 ^ | ||
697 | * a=-fIFOut-fIFBW/2 -a=+fIFOut+fIFBW/2 | ||
698 | * | ||
699 | * Note that some equations are doubled to prevent round-off | ||
700 | * problems when calculating fIFBW/2 | ||
701 | * | ||
702 | * @pAS_Info: Avoid Spurs information block | ||
703 | * @fm: If spur, amount f_IF1 has to move negative | ||
704 | * @fp: If spur, amount f_IF1 has to move positive | ||
705 | * | ||
706 | * Returns 1 if an LO spur would be present, otherwise 0. | ||
707 | */ | ||
708 | static u32 IsSpurInBand(struct MT2063_AvoidSpursData_t *pAS_Info, | ||
709 | u32 *fm, u32 * fp) | ||
710 | { | ||
711 | /* | ||
712 | ** Calculate LO frequency settings. | ||
713 | */ | ||
714 | u32 n, n0; | ||
715 | const u32 f_LO1 = pAS_Info->f_LO1; | ||
716 | const u32 f_LO2 = pAS_Info->f_LO2; | ||
717 | const u32 d = pAS_Info->f_out + pAS_Info->f_out_bw / 2; | ||
718 | const u32 c = d - pAS_Info->f_out_bw; | ||
719 | const u32 f = pAS_Info->f_zif_bw / 2; | ||
720 | const u32 f_Scale = (f_LO1 / (UINT_MAX / 2 / pAS_Info->maxH1)) + 1; | ||
721 | s32 f_nsLO1, f_nsLO2; | ||
722 | s32 f_Spur; | ||
723 | u32 ma, mb, mc, md, me, mf; | ||
724 | u32 lo_gcd, gd_Scale, gc_Scale, gf_Scale, hgds, hgfs, hgcs; | ||
725 | |||
726 | dprintk(2, "\n"); | ||
727 | |||
728 | *fm = 0; | ||
729 | |||
730 | /* | ||
731 | ** For each edge (d, c & f), calculate a scale, based on the gcd | ||
732 | ** of f_LO1, f_LO2 and the edge value. Use the larger of this | ||
733 | ** gcd-based scale factor or f_Scale. | ||
734 | */ | ||
735 | lo_gcd = MT2063_gcd(f_LO1, f_LO2); | ||
736 | gd_Scale = max((u32) MT2063_gcd(lo_gcd, d), f_Scale); | ||
737 | hgds = gd_Scale / 2; | ||
738 | gc_Scale = max((u32) MT2063_gcd(lo_gcd, c), f_Scale); | ||
739 | hgcs = gc_Scale / 2; | ||
740 | gf_Scale = max((u32) MT2063_gcd(lo_gcd, f), f_Scale); | ||
741 | hgfs = gf_Scale / 2; | ||
742 | |||
743 | n0 = DIV_ROUND_UP(f_LO2 - d, f_LO1 - f_LO2); | ||
744 | |||
745 | /* Check out all multiples of LO1 from n0 to m_maxLOSpurHarmonic */ | ||
746 | for (n = n0; n <= pAS_Info->maxH1; ++n) { | ||
747 | md = (n * ((f_LO1 + hgds) / gd_Scale) - | ||
748 | ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale); | ||
749 | |||
750 | /* If # fLO2 harmonics > m_maxLOSpurHarmonic, then no spurs present */ | ||
751 | if (md >= pAS_Info->maxH1) | ||
752 | break; | ||
753 | |||
754 | ma = (n * ((f_LO1 + hgds) / gd_Scale) + | ||
755 | ((d + hgds) / gd_Scale)) / ((f_LO2 + hgds) / gd_Scale); | ||
756 | |||
757 | /* If no spurs between +/- (f_out + f_IFBW/2), then try next harmonic */ | ||
758 | if (md == ma) | ||
759 | continue; | ||
760 | |||
761 | mc = (n * ((f_LO1 + hgcs) / gc_Scale) - | ||
762 | ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale); | ||
763 | if (mc != md) { | ||
764 | f_nsLO1 = (s32) (n * (f_LO1 / gc_Scale)); | ||
765 | f_nsLO2 = (s32) (mc * (f_LO2 / gc_Scale)); | ||
766 | f_Spur = | ||
767 | (gc_Scale * (f_nsLO1 - f_nsLO2)) + | ||
768 | n * (f_LO1 % gc_Scale) - mc * (f_LO2 % gc_Scale); | ||
769 | |||
770 | *fp = ((f_Spur - (s32) c) / (mc - n)) + 1; | ||
771 | *fm = (((s32) d - f_Spur) / (mc - n)) + 1; | ||
772 | return 1; | ||
773 | } | ||
774 | |||
775 | /* Location of Zero-IF-spur to be checked */ | ||
776 | me = (n * ((f_LO1 + hgfs) / gf_Scale) + | ||
777 | ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale); | ||
778 | mf = (n * ((f_LO1 + hgfs) / gf_Scale) - | ||
779 | ((f + hgfs) / gf_Scale)) / ((f_LO2 + hgfs) / gf_Scale); | ||
780 | if (me != mf) { | ||
781 | f_nsLO1 = n * (f_LO1 / gf_Scale); | ||
782 | f_nsLO2 = me * (f_LO2 / gf_Scale); | ||
783 | f_Spur = | ||
784 | (gf_Scale * (f_nsLO1 - f_nsLO2)) + | ||
785 | n * (f_LO1 % gf_Scale) - me * (f_LO2 % gf_Scale); | ||
786 | |||
787 | *fp = ((f_Spur + (s32) f) / (me - n)) + 1; | ||
788 | *fm = (((s32) f - f_Spur) / (me - n)) + 1; | ||
789 | return 1; | ||
790 | } | ||
791 | |||
792 | mb = (n * ((f_LO1 + hgcs) / gc_Scale) + | ||
793 | ((c + hgcs) / gc_Scale)) / ((f_LO2 + hgcs) / gc_Scale); | ||
794 | if (ma != mb) { | ||
795 | f_nsLO1 = n * (f_LO1 / gc_Scale); | ||
796 | f_nsLO2 = ma * (f_LO2 / gc_Scale); | ||
797 | f_Spur = | ||
798 | (gc_Scale * (f_nsLO1 - f_nsLO2)) + | ||
799 | n * (f_LO1 % gc_Scale) - ma * (f_LO2 % gc_Scale); | ||
800 | |||
801 | *fp = (((s32) d + f_Spur) / (ma - n)) + 1; | ||
802 | *fm = (-(f_Spur + (s32) c) / (ma - n)) + 1; | ||
803 | return 1; | ||
804 | } | ||
805 | } | ||
806 | |||
807 | /* No spurs found */ | ||
808 | return 0; | ||
809 | } | ||
810 | |||
811 | /* | ||
812 | * MT_AvoidSpurs() - Main entry point to avoid spurs. | ||
813 | * Checks for existing spurs in present LO1, LO2 freqs | ||
814 | * and if present, chooses spur-free LO1, LO2 combination | ||
815 | * that tunes the same input/output frequencies. | ||
816 | */ | ||
817 | static u32 MT2063_AvoidSpurs(struct MT2063_AvoidSpursData_t *pAS_Info) | ||
818 | { | ||
819 | u32 status = 0; | ||
820 | u32 fm, fp; /* restricted range on LO's */ | ||
821 | pAS_Info->bSpurAvoided = 0; | ||
822 | pAS_Info->nSpursFound = 0; | ||
823 | |||
824 | dprintk(2, "\n"); | ||
825 | |||
826 | if (pAS_Info->maxH1 == 0) | ||
827 | return 0; | ||
828 | |||
829 | /* | ||
830 | * Avoid LO Generated Spurs | ||
831 | * | ||
832 | * Make sure that have no LO-related spurs within the IF output | ||
833 | * bandwidth. | ||
834 | * | ||
835 | * If there is an LO spur in this band, start at the current IF1 frequency | ||
836 | * and work out until we find a spur-free frequency or run up against the | ||
837 | * 1st IF SAW band edge. Use temporary copies of fLO1 and fLO2 so that they | ||
838 | * will be unchanged if a spur-free setting is not found. | ||
839 | */ | ||
840 | pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp); | ||
841 | if (pAS_Info->bSpurPresent) { | ||
842 | u32 zfIF1 = pAS_Info->f_LO1 - pAS_Info->f_in; /* current attempt at a 1st IF */ | ||
843 | u32 zfLO1 = pAS_Info->f_LO1; /* current attempt at an LO1 freq */ | ||
844 | u32 zfLO2 = pAS_Info->f_LO2; /* current attempt at an LO2 freq */ | ||
845 | u32 delta_IF1; | ||
846 | u32 new_IF1; | ||
847 | |||
848 | /* | ||
849 | ** Spur was found, attempt to find a spur-free 1st IF | ||
850 | */ | ||
851 | do { | ||
852 | pAS_Info->nSpursFound++; | ||
853 | |||
854 | /* Raise f_IF1_upper, if needed */ | ||
855 | MT2063_AddExclZone(pAS_Info, zfIF1 - fm, zfIF1 + fp); | ||
856 | |||
857 | /* Choose next IF1 that is closest to f_IF1_CENTER */ | ||
858 | new_IF1 = MT2063_ChooseFirstIF(pAS_Info); | ||
859 | |||
860 | if (new_IF1 > zfIF1) { | ||
861 | pAS_Info->f_LO1 += (new_IF1 - zfIF1); | ||
862 | pAS_Info->f_LO2 += (new_IF1 - zfIF1); | ||
863 | } else { | ||
864 | pAS_Info->f_LO1 -= (zfIF1 - new_IF1); | ||
865 | pAS_Info->f_LO2 -= (zfIF1 - new_IF1); | ||
866 | } | ||
867 | zfIF1 = new_IF1; | ||
868 | |||
869 | if (zfIF1 > pAS_Info->f_if1_Center) | ||
870 | delta_IF1 = zfIF1 - pAS_Info->f_if1_Center; | ||
871 | else | ||
872 | delta_IF1 = pAS_Info->f_if1_Center - zfIF1; | ||
873 | |||
874 | pAS_Info->bSpurPresent = IsSpurInBand(pAS_Info, &fm, &fp); | ||
875 | /* | ||
876 | * Continue while the new 1st IF is still within the 1st IF bandwidth | ||
877 | * and there is a spur in the band (again) | ||
878 | */ | ||
879 | } while ((2 * delta_IF1 + pAS_Info->f_out_bw <= pAS_Info->f_if1_bw) && pAS_Info->bSpurPresent); | ||
880 | |||
881 | /* | ||
882 | * Use the LO-spur free values found. If the search went all | ||
883 | * the way to the 1st IF band edge and always found spurs, just | ||
884 | * leave the original choice. It's as "good" as any other. | ||
885 | */ | ||
886 | if (pAS_Info->bSpurPresent == 1) { | ||
887 | status |= MT2063_SPUR_PRESENT_ERR; | ||
888 | pAS_Info->f_LO1 = zfLO1; | ||
889 | pAS_Info->f_LO2 = zfLO2; | ||
890 | } else | ||
891 | pAS_Info->bSpurAvoided = 1; | ||
892 | } | ||
893 | |||
894 | status |= | ||
895 | ((pAS_Info-> | ||
896 | nSpursFound << MT2063_SPUR_SHIFT) & MT2063_SPUR_CNT_MASK); | ||
897 | |||
898 | return status; | ||
899 | } | ||
900 | |||
901 | /* | ||
902 | * Constants used by the tuning algorithm | ||
903 | */ | ||
904 | #define MT2063_REF_FREQ (16000000UL) /* Reference oscillator Frequency (in Hz) */ | ||
905 | #define MT2063_IF1_BW (22000000UL) /* The IF1 filter bandwidth (in Hz) */ | ||
906 | #define MT2063_TUNE_STEP_SIZE (50000UL) /* Tune in steps of 50 kHz */ | ||
907 | #define MT2063_SPUR_STEP_HZ (250000UL) /* Step size (in Hz) to move IF1 when avoiding spurs */ | ||
908 | #define MT2063_ZIF_BW (2000000UL) /* Zero-IF spur-free bandwidth (in Hz) */ | ||
909 | #define MT2063_MAX_HARMONICS_1 (15UL) /* Highest intra-tuner LO Spur Harmonic to be avoided */ | ||
910 | #define MT2063_MAX_HARMONICS_2 (5UL) /* Highest inter-tuner LO Spur Harmonic to be avoided */ | ||
911 | #define MT2063_MIN_LO_SEP (1000000UL) /* Minimum inter-tuner LO frequency separation */ | ||
912 | #define MT2063_LO1_FRACN_AVOID (0UL) /* LO1 FracN numerator avoid region (in Hz) */ | ||
913 | #define MT2063_LO2_FRACN_AVOID (199999UL) /* LO2 FracN numerator avoid region (in Hz) */ | ||
914 | #define MT2063_MIN_FIN_FREQ (44000000UL) /* Minimum input frequency (in Hz) */ | ||
915 | #define MT2063_MAX_FIN_FREQ (1100000000UL) /* Maximum input frequency (in Hz) */ | ||
916 | #define MT2063_MIN_FOUT_FREQ (36000000UL) /* Minimum output frequency (in Hz) */ | ||
917 | #define MT2063_MAX_FOUT_FREQ (57000000UL) /* Maximum output frequency (in Hz) */ | ||
918 | #define MT2063_MIN_DNC_FREQ (1293000000UL) /* Minimum LO2 frequency (in Hz) */ | ||
919 | #define MT2063_MAX_DNC_FREQ (1614000000UL) /* Maximum LO2 frequency (in Hz) */ | ||
920 | #define MT2063_MIN_UPC_FREQ (1396000000UL) /* Minimum LO1 frequency (in Hz) */ | ||
921 | #define MT2063_MAX_UPC_FREQ (2750000000UL) /* Maximum LO1 frequency (in Hz) */ | ||
922 | |||
923 | /* | ||
924 | * Define the supported Part/Rev codes for the MT2063 | ||
925 | */ | ||
926 | #define MT2063_B0 (0x9B) | ||
927 | #define MT2063_B1 (0x9C) | ||
928 | #define MT2063_B2 (0x9D) | ||
929 | #define MT2063_B3 (0x9E) | ||
930 | |||
931 | /** | ||
932 | * mt2063_lockStatus - Checks to see if LO1 and LO2 are locked | ||
933 | * | ||
934 | * @state: struct mt2063_state pointer | ||
935 | * | ||
936 | * This function returns 0, if no lock, 1 if locked and a value < 1 if error | ||
937 | */ | ||
938 | static unsigned int mt2063_lockStatus(struct mt2063_state *state) | ||
939 | { | ||
940 | const u32 nMaxWait = 100; /* wait a maximum of 100 msec */ | ||
941 | const u32 nPollRate = 2; /* poll status bits every 2 ms */ | ||
942 | const u32 nMaxLoops = nMaxWait / nPollRate; | ||
943 | const u8 LO1LK = 0x80; | ||
944 | u8 LO2LK = 0x08; | ||
945 | u32 status; | ||
946 | u32 nDelays = 0; | ||
947 | |||
948 | dprintk(2, "\n"); | ||
949 | |||
950 | /* LO2 Lock bit was in a different place for B0 version */ | ||
951 | if (state->tuner_id == MT2063_B0) | ||
952 | LO2LK = 0x40; | ||
953 | |||
954 | do { | ||
955 | status = mt2063_read(state, MT2063_REG_LO_STATUS, | ||
956 | &state->reg[MT2063_REG_LO_STATUS], 1); | ||
957 | |||
958 | if (status < 0) | ||
959 | return status; | ||
960 | |||
961 | if ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) == | ||
962 | (LO1LK | LO2LK)) { | ||
963 | return TUNER_STATUS_LOCKED | TUNER_STATUS_STEREO; | ||
964 | } | ||
965 | msleep(nPollRate); /* Wait between retries */ | ||
966 | } while (++nDelays < nMaxLoops); | ||
967 | |||
968 | /* | ||
969 | * Got no lock or partial lock | ||
970 | */ | ||
971 | return 0; | ||
972 | } | ||
973 | |||
974 | /* | ||
975 | * Constants for setting receiver modes. | ||
976 | * (6 modes defined at this time, enumerated by mt2063_delivery_sys) | ||
977 | * (DNC1GC & DNC2GC are the values, which are used, when the specific | ||
978 | * DNC Output is selected, the other is always off) | ||
979 | * | ||
980 | * enum mt2063_delivery_sys | ||
981 | * -------------+---------------------------------------------- | ||
982 | * Mode 0 : | MT2063_CABLE_QAM | ||
983 | * Mode 1 : | MT2063_CABLE_ANALOG | ||
984 | * Mode 2 : | MT2063_OFFAIR_COFDM | ||
985 | * Mode 3 : | MT2063_OFFAIR_COFDM_SAWLESS | ||
986 | * Mode 4 : | MT2063_OFFAIR_ANALOG | ||
987 | * Mode 5 : | MT2063_OFFAIR_8VSB | ||
988 | * --------------+---------------------------------------------- | ||
989 | * | ||
990 | * |<---------- Mode -------------->| | ||
991 | * Reg Field | 0 | 1 | 2 | 3 | 4 | 5 | | ||
992 | * ------------+-----+-----+-----+-----+-----+-----+ | ||
993 | * RFAGCen | OFF | OFF | OFF | OFF | OFF | OFF | ||
994 | * LNARin | 0 | 0 | 3 | 3 | 3 | 3 | ||
995 | * FIFFQen | 1 | 1 | 1 | 1 | 1 | 1 | ||
996 | * FIFFq | 0 | 0 | 0 | 0 | 0 | 0 | ||
997 | * DNC1gc | 0 | 0 | 0 | 0 | 0 | 0 | ||
998 | * DNC2gc | 0 | 0 | 0 | 0 | 0 | 0 | ||
999 | * GCU Auto | 1 | 1 | 1 | 1 | 1 | 1 | ||
1000 | * LNA max Atn | 31 | 31 | 31 | 31 | 31 | 31 | ||
1001 | * LNA Target | 44 | 43 | 43 | 43 | 43 | 43 | ||
1002 | * ign RF Ovl | 0 | 0 | 0 | 0 | 0 | 0 | ||
1003 | * RF max Atn | 31 | 31 | 31 | 31 | 31 | 31 | ||
1004 | * PD1 Target | 36 | 36 | 38 | 38 | 36 | 38 | ||
1005 | * ign FIF Ovl | 0 | 0 | 0 | 0 | 0 | 0 | ||
1006 | * FIF max Atn | 5 | 5 | 5 | 5 | 5 | 5 | ||
1007 | * PD2 Target | 40 | 33 | 42 | 42 | 33 | 42 | ||
1008 | */ | ||
1009 | |||
1010 | enum mt2063_delivery_sys { | ||
1011 | MT2063_CABLE_QAM = 0, | ||
1012 | MT2063_CABLE_ANALOG, | ||
1013 | MT2063_OFFAIR_COFDM, | ||
1014 | MT2063_OFFAIR_COFDM_SAWLESS, | ||
1015 | MT2063_OFFAIR_ANALOG, | ||
1016 | MT2063_OFFAIR_8VSB, | ||
1017 | MT2063_NUM_RCVR_MODES | ||
1018 | }; | ||
1019 | |||
1020 | static const char *mt2063_mode_name[] = { | ||
1021 | [MT2063_CABLE_QAM] = "digital cable", | ||
1022 | [MT2063_CABLE_ANALOG] = "analog cable", | ||
1023 | [MT2063_OFFAIR_COFDM] = "digital offair", | ||
1024 | [MT2063_OFFAIR_COFDM_SAWLESS] = "digital offair without SAW", | ||
1025 | [MT2063_OFFAIR_ANALOG] = "analog offair", | ||
1026 | [MT2063_OFFAIR_8VSB] = "analog offair 8vsb", | ||
1027 | }; | ||
1028 | |||
1029 | static const u8 RFAGCEN[] = { 0, 0, 0, 0, 0, 0 }; | ||
1030 | static const u8 LNARIN[] = { 0, 0, 3, 3, 3, 3 }; | ||
1031 | static const u8 FIFFQEN[] = { 1, 1, 1, 1, 1, 1 }; | ||
1032 | static const u8 FIFFQ[] = { 0, 0, 0, 0, 0, 0 }; | ||
1033 | static const u8 DNC1GC[] = { 0, 0, 0, 0, 0, 0 }; | ||
1034 | static const u8 DNC2GC[] = { 0, 0, 0, 0, 0, 0 }; | ||
1035 | static const u8 ACLNAMAX[] = { 31, 31, 31, 31, 31, 31 }; | ||
1036 | static const u8 LNATGT[] = { 44, 43, 43, 43, 43, 43 }; | ||
1037 | static const u8 RFOVDIS[] = { 0, 0, 0, 0, 0, 0 }; | ||
1038 | static const u8 ACRFMAX[] = { 31, 31, 31, 31, 31, 31 }; | ||
1039 | static const u8 PD1TGT[] = { 36, 36, 38, 38, 36, 38 }; | ||
1040 | static const u8 FIFOVDIS[] = { 0, 0, 0, 0, 0, 0 }; | ||
1041 | static const u8 ACFIFMAX[] = { 29, 29, 29, 29, 29, 29 }; | ||
1042 | static const u8 PD2TGT[] = { 40, 33, 38, 42, 30, 38 }; | ||
1043 | |||
1044 | /* | ||
1045 | * mt2063_set_dnc_output_enable() | ||
1046 | */ | ||
1047 | static u32 mt2063_get_dnc_output_enable(struct mt2063_state *state, | ||
1048 | enum MT2063_DNC_Output_Enable *pValue) | ||
1049 | { | ||
1050 | dprintk(2, "\n"); | ||
1051 | |||
1052 | if ((state->reg[MT2063_REG_DNC_GAIN] & 0x03) == 0x03) { /* if DNC1 is off */ | ||
1053 | if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */ | ||
1054 | *pValue = MT2063_DNC_NONE; | ||
1055 | else | ||
1056 | *pValue = MT2063_DNC_2; | ||
1057 | } else { /* DNC1 is on */ | ||
1058 | if ((state->reg[MT2063_REG_VGA_GAIN] & 0x03) == 0x03) /* if DNC2 is off */ | ||
1059 | *pValue = MT2063_DNC_1; | ||
1060 | else | ||
1061 | *pValue = MT2063_DNC_BOTH; | ||
1062 | } | ||
1063 | return 0; | ||
1064 | } | ||
1065 | |||
1066 | /* | ||
1067 | * mt2063_set_dnc_output_enable() | ||
1068 | */ | ||
1069 | static u32 mt2063_set_dnc_output_enable(struct mt2063_state *state, | ||
1070 | enum MT2063_DNC_Output_Enable nValue) | ||
1071 | { | ||
1072 | u32 status = 0; /* Status to be returned */ | ||
1073 | u8 val = 0; | ||
1074 | |||
1075 | dprintk(2, "\n"); | ||
1076 | |||
1077 | /* selects, which DNC output is used */ | ||
1078 | switch (nValue) { | ||
1079 | case MT2063_DNC_NONE: | ||
1080 | val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */ | ||
1081 | if (state->reg[MT2063_REG_DNC_GAIN] != | ||
1082 | val) | ||
1083 | status |= | ||
1084 | mt2063_setreg(state, | ||
1085 | MT2063_REG_DNC_GAIN, | ||
1086 | val); | ||
1087 | |||
1088 | val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */ | ||
1089 | if (state->reg[MT2063_REG_VGA_GAIN] != | ||
1090 | val) | ||
1091 | status |= | ||
1092 | mt2063_setreg(state, | ||
1093 | MT2063_REG_VGA_GAIN, | ||
1094 | val); | ||
1095 | |||
1096 | val = (state->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */ | ||
1097 | if (state->reg[MT2063_REG_RSVD_20] != | ||
1098 | val) | ||
1099 | status |= | ||
1100 | mt2063_setreg(state, | ||
1101 | MT2063_REG_RSVD_20, | ||
1102 | val); | ||
1103 | |||
1104 | break; | ||
1105 | case MT2063_DNC_1: | ||
1106 | val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03); /* Set DNC1GC=x */ | ||
1107 | if (state->reg[MT2063_REG_DNC_GAIN] != | ||
1108 | val) | ||
1109 | status |= | ||
1110 | mt2063_setreg(state, | ||
1111 | MT2063_REG_DNC_GAIN, | ||
1112 | val); | ||
1113 | |||
1114 | val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | 0x03; /* Set DNC2GC=3 */ | ||
1115 | if (state->reg[MT2063_REG_VGA_GAIN] != | ||
1116 | val) | ||
1117 | status |= | ||
1118 | mt2063_setreg(state, | ||
1119 | MT2063_REG_VGA_GAIN, | ||
1120 | val); | ||
1121 | |||
1122 | val = (state->reg[MT2063_REG_RSVD_20] & ~0x40); /* Set PD2MUX=0 */ | ||
1123 | if (state->reg[MT2063_REG_RSVD_20] != | ||
1124 | val) | ||
1125 | status |= | ||
1126 | mt2063_setreg(state, | ||
1127 | MT2063_REG_RSVD_20, | ||
1128 | val); | ||
1129 | |||
1130 | break; | ||
1131 | case MT2063_DNC_2: | ||
1132 | val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | 0x03; /* Set DNC1GC=3 */ | ||
1133 | if (state->reg[MT2063_REG_DNC_GAIN] != | ||
1134 | val) | ||
1135 | status |= | ||
1136 | mt2063_setreg(state, | ||
1137 | MT2063_REG_DNC_GAIN, | ||
1138 | val); | ||
1139 | |||
1140 | val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03); /* Set DNC2GC=x */ | ||
1141 | if (state->reg[MT2063_REG_VGA_GAIN] != | ||
1142 | val) | ||
1143 | status |= | ||
1144 | mt2063_setreg(state, | ||
1145 | MT2063_REG_VGA_GAIN, | ||
1146 | val); | ||
1147 | |||
1148 | val = (state->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */ | ||
1149 | if (state->reg[MT2063_REG_RSVD_20] != | ||
1150 | val) | ||
1151 | status |= | ||
1152 | mt2063_setreg(state, | ||
1153 | MT2063_REG_RSVD_20, | ||
1154 | val); | ||
1155 | |||
1156 | break; | ||
1157 | case MT2063_DNC_BOTH: | ||
1158 | val = (state->reg[MT2063_REG_DNC_GAIN] & 0xFC) | (DNC1GC[state->rcvr_mode] & 0x03); /* Set DNC1GC=x */ | ||
1159 | if (state->reg[MT2063_REG_DNC_GAIN] != | ||
1160 | val) | ||
1161 | status |= | ||
1162 | mt2063_setreg(state, | ||
1163 | MT2063_REG_DNC_GAIN, | ||
1164 | val); | ||
1165 | |||
1166 | val = (state->reg[MT2063_REG_VGA_GAIN] & 0xFC) | (DNC2GC[state->rcvr_mode] & 0x03); /* Set DNC2GC=x */ | ||
1167 | if (state->reg[MT2063_REG_VGA_GAIN] != | ||
1168 | val) | ||
1169 | status |= | ||
1170 | mt2063_setreg(state, | ||
1171 | MT2063_REG_VGA_GAIN, | ||
1172 | val); | ||
1173 | |||
1174 | val = (state->reg[MT2063_REG_RSVD_20] | 0x40); /* Set PD2MUX=1 */ | ||
1175 | if (state->reg[MT2063_REG_RSVD_20] != | ||
1176 | val) | ||
1177 | status |= | ||
1178 | mt2063_setreg(state, | ||
1179 | MT2063_REG_RSVD_20, | ||
1180 | val); | ||
1181 | |||
1182 | break; | ||
1183 | default: | ||
1184 | break; | ||
1185 | } | ||
1186 | |||
1187 | return status; | ||
1188 | } | ||
1189 | |||
1190 | /* | ||
1191 | * MT2063_SetReceiverMode() - Set the MT2063 receiver mode, according with | ||
1192 | * the selected enum mt2063_delivery_sys type. | ||
1193 | * | ||
1194 | * (DNC1GC & DNC2GC are the values, which are used, when the specific | ||
1195 | * DNC Output is selected, the other is always off) | ||
1196 | * | ||
1197 | * @state: ptr to mt2063_state structure | ||
1198 | * @Mode: desired reciever delivery system | ||
1199 | * | ||
1200 | * Note: Register cache must be valid for it to work | ||
1201 | */ | ||
1202 | |||
1203 | static u32 MT2063_SetReceiverMode(struct mt2063_state *state, | ||
1204 | enum mt2063_delivery_sys Mode) | ||
1205 | { | ||
1206 | u32 status = 0; /* Status to be returned */ | ||
1207 | u8 val; | ||
1208 | u32 longval; | ||
1209 | |||
1210 | dprintk(2, "\n"); | ||
1211 | |||
1212 | if (Mode >= MT2063_NUM_RCVR_MODES) | ||
1213 | status = -ERANGE; | ||
1214 | |||
1215 | /* RFAGCen */ | ||
1216 | if (status >= 0) { | ||
1217 | val = | ||
1218 | (state-> | ||
1219 | reg[MT2063_REG_PD1_TGT] & (u8) ~0x40) | (RFAGCEN[Mode] | ||
1220 | ? 0x40 : | ||
1221 | 0x00); | ||
1222 | if (state->reg[MT2063_REG_PD1_TGT] != val) | ||
1223 | status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val); | ||
1224 | } | ||
1225 | |||
1226 | /* LNARin */ | ||
1227 | if (status >= 0) { | ||
1228 | u8 val = (state->reg[MT2063_REG_CTRL_2C] & (u8) ~0x03) | | ||
1229 | (LNARIN[Mode] & 0x03); | ||
1230 | if (state->reg[MT2063_REG_CTRL_2C] != val) | ||
1231 | status |= mt2063_setreg(state, MT2063_REG_CTRL_2C, val); | ||
1232 | } | ||
1233 | |||
1234 | /* FIFFQEN and FIFFQ */ | ||
1235 | if (status >= 0) { | ||
1236 | val = | ||
1237 | (state-> | ||
1238 | reg[MT2063_REG_FIFF_CTRL2] & (u8) ~0xF0) | | ||
1239 | (FIFFQEN[Mode] << 7) | (FIFFQ[Mode] << 4); | ||
1240 | if (state->reg[MT2063_REG_FIFF_CTRL2] != val) { | ||
1241 | status |= | ||
1242 | mt2063_setreg(state, MT2063_REG_FIFF_CTRL2, val); | ||
1243 | /* trigger FIFF calibration, needed after changing FIFFQ */ | ||
1244 | val = | ||
1245 | (state->reg[MT2063_REG_FIFF_CTRL] | (u8) 0x01); | ||
1246 | status |= | ||
1247 | mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val); | ||
1248 | val = | ||
1249 | (state-> | ||
1250 | reg[MT2063_REG_FIFF_CTRL] & (u8) ~0x01); | ||
1251 | status |= | ||
1252 | mt2063_setreg(state, MT2063_REG_FIFF_CTRL, val); | ||
1253 | } | ||
1254 | } | ||
1255 | |||
1256 | /* DNC1GC & DNC2GC */ | ||
1257 | status |= mt2063_get_dnc_output_enable(state, &longval); | ||
1258 | status |= mt2063_set_dnc_output_enable(state, longval); | ||
1259 | |||
1260 | /* acLNAmax */ | ||
1261 | if (status >= 0) { | ||
1262 | u8 val = (state->reg[MT2063_REG_LNA_OV] & (u8) ~0x1F) | | ||
1263 | (ACLNAMAX[Mode] & 0x1F); | ||
1264 | if (state->reg[MT2063_REG_LNA_OV] != val) | ||
1265 | status |= mt2063_setreg(state, MT2063_REG_LNA_OV, val); | ||
1266 | } | ||
1267 | |||
1268 | /* LNATGT */ | ||
1269 | if (status >= 0) { | ||
1270 | u8 val = (state->reg[MT2063_REG_LNA_TGT] & (u8) ~0x3F) | | ||
1271 | (LNATGT[Mode] & 0x3F); | ||
1272 | if (state->reg[MT2063_REG_LNA_TGT] != val) | ||
1273 | status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val); | ||
1274 | } | ||
1275 | |||
1276 | /* ACRF */ | ||
1277 | if (status >= 0) { | ||
1278 | u8 val = (state->reg[MT2063_REG_RF_OV] & (u8) ~0x1F) | | ||
1279 | (ACRFMAX[Mode] & 0x1F); | ||
1280 | if (state->reg[MT2063_REG_RF_OV] != val) | ||
1281 | status |= mt2063_setreg(state, MT2063_REG_RF_OV, val); | ||
1282 | } | ||
1283 | |||
1284 | /* PD1TGT */ | ||
1285 | if (status >= 0) { | ||
1286 | u8 val = (state->reg[MT2063_REG_PD1_TGT] & (u8) ~0x3F) | | ||
1287 | (PD1TGT[Mode] & 0x3F); | ||
1288 | if (state->reg[MT2063_REG_PD1_TGT] != val) | ||
1289 | status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val); | ||
1290 | } | ||
1291 | |||
1292 | /* FIFATN */ | ||
1293 | if (status >= 0) { | ||
1294 | u8 val = ACFIFMAX[Mode]; | ||
1295 | if (state->reg[MT2063_REG_PART_REV] != MT2063_B3 && val > 5) | ||
1296 | val = 5; | ||
1297 | val = (state->reg[MT2063_REG_FIF_OV] & (u8) ~0x1F) | | ||
1298 | (val & 0x1F); | ||
1299 | if (state->reg[MT2063_REG_FIF_OV] != val) | ||
1300 | status |= mt2063_setreg(state, MT2063_REG_FIF_OV, val); | ||
1301 | } | ||
1302 | |||
1303 | /* PD2TGT */ | ||
1304 | if (status >= 0) { | ||
1305 | u8 val = (state->reg[MT2063_REG_PD2_TGT] & (u8) ~0x3F) | | ||
1306 | (PD2TGT[Mode] & 0x3F); | ||
1307 | if (state->reg[MT2063_REG_PD2_TGT] != val) | ||
1308 | status |= mt2063_setreg(state, MT2063_REG_PD2_TGT, val); | ||
1309 | } | ||
1310 | |||
1311 | /* Ignore ATN Overload */ | ||
1312 | if (status >= 0) { | ||
1313 | val = (state->reg[MT2063_REG_LNA_TGT] & (u8) ~0x80) | | ||
1314 | (RFOVDIS[Mode] ? 0x80 : 0x00); | ||
1315 | if (state->reg[MT2063_REG_LNA_TGT] != val) | ||
1316 | status |= mt2063_setreg(state, MT2063_REG_LNA_TGT, val); | ||
1317 | } | ||
1318 | |||
1319 | /* Ignore FIF Overload */ | ||
1320 | if (status >= 0) { | ||
1321 | val = (state->reg[MT2063_REG_PD1_TGT] & (u8) ~0x80) | | ||
1322 | (FIFOVDIS[Mode] ? 0x80 : 0x00); | ||
1323 | if (state->reg[MT2063_REG_PD1_TGT] != val) | ||
1324 | status |= mt2063_setreg(state, MT2063_REG_PD1_TGT, val); | ||
1325 | } | ||
1326 | |||
1327 | if (status >= 0) { | ||
1328 | state->rcvr_mode = Mode; | ||
1329 | dprintk(1, "mt2063 mode changed to %s\n", | ||
1330 | mt2063_mode_name[state->rcvr_mode]); | ||
1331 | } | ||
1332 | |||
1333 | return status; | ||
1334 | } | ||
1335 | |||
1336 | /* | ||
1337 | * MT2063_ClearPowerMaskBits () - Clears the power-down mask bits for various | ||
1338 | * sections of the MT2063 | ||
1339 | * | ||
1340 | * @Bits: Mask bits to be cleared. | ||
1341 | * | ||
1342 | * See definition of MT2063_Mask_Bits type for description | ||
1343 | * of each of the power bits. | ||
1344 | */ | ||
1345 | static u32 MT2063_ClearPowerMaskBits(struct mt2063_state *state, | ||
1346 | enum MT2063_Mask_Bits Bits) | ||
1347 | { | ||
1348 | u32 status = 0; | ||
1349 | |||
1350 | dprintk(2, "\n"); | ||
1351 | Bits = (enum MT2063_Mask_Bits)(Bits & MT2063_ALL_SD); /* Only valid bits for this tuner */ | ||
1352 | if ((Bits & 0xFF00) != 0) { | ||
1353 | state->reg[MT2063_REG_PWR_2] &= ~(u8) (Bits >> 8); | ||
1354 | status |= | ||
1355 | mt2063_write(state, | ||
1356 | MT2063_REG_PWR_2, | ||
1357 | &state->reg[MT2063_REG_PWR_2], 1); | ||
1358 | } | ||
1359 | if ((Bits & 0xFF) != 0) { | ||
1360 | state->reg[MT2063_REG_PWR_1] &= ~(u8) (Bits & 0xFF); | ||
1361 | status |= | ||
1362 | mt2063_write(state, | ||
1363 | MT2063_REG_PWR_1, | ||
1364 | &state->reg[MT2063_REG_PWR_1], 1); | ||
1365 | } | ||
1366 | |||
1367 | return status; | ||
1368 | } | ||
1369 | |||
1370 | /* | ||
1371 | * MT2063_SoftwareShutdown() - Enables or disables software shutdown function. | ||
1372 | * When Shutdown is 1, any section whose power | ||
1373 | * mask is set will be shutdown. | ||
1374 | */ | ||
1375 | static u32 MT2063_SoftwareShutdown(struct mt2063_state *state, u8 Shutdown) | ||
1376 | { | ||
1377 | u32 status; | ||
1378 | |||
1379 | dprintk(2, "\n"); | ||
1380 | if (Shutdown == 1) | ||
1381 | state->reg[MT2063_REG_PWR_1] |= 0x04; | ||
1382 | else | ||
1383 | state->reg[MT2063_REG_PWR_1] &= ~0x04; | ||
1384 | |||
1385 | status = mt2063_write(state, | ||
1386 | MT2063_REG_PWR_1, | ||
1387 | &state->reg[MT2063_REG_PWR_1], 1); | ||
1388 | |||
1389 | if (Shutdown != 1) { | ||
1390 | state->reg[MT2063_REG_BYP_CTRL] = | ||
1391 | (state->reg[MT2063_REG_BYP_CTRL] & 0x9F) | 0x40; | ||
1392 | status |= | ||
1393 | mt2063_write(state, | ||
1394 | MT2063_REG_BYP_CTRL, | ||
1395 | &state->reg[MT2063_REG_BYP_CTRL], | ||
1396 | 1); | ||
1397 | state->reg[MT2063_REG_BYP_CTRL] = | ||
1398 | (state->reg[MT2063_REG_BYP_CTRL] & 0x9F); | ||
1399 | status |= | ||
1400 | mt2063_write(state, | ||
1401 | MT2063_REG_BYP_CTRL, | ||
1402 | &state->reg[MT2063_REG_BYP_CTRL], | ||
1403 | 1); | ||
1404 | } | ||
1405 | |||
1406 | return status; | ||
1407 | } | ||
1408 | |||
1409 | static u32 MT2063_Round_fLO(u32 f_LO, u32 f_LO_Step, u32 f_ref) | ||
1410 | { | ||
1411 | return f_ref * (f_LO / f_ref) | ||
1412 | + f_LO_Step * (((f_LO % f_ref) + (f_LO_Step / 2)) / f_LO_Step); | ||
1413 | } | ||
1414 | |||
1415 | /** | ||
1416 | * fLO_FractionalTerm() - Calculates the portion contributed by FracN / denom. | ||
1417 | * This function preserves maximum precision without | ||
1418 | * risk of overflow. It accurately calculates | ||
1419 | * f_ref * num / denom to within 1 HZ with fixed math. | ||
1420 | * | ||
1421 | * @num : Fractional portion of the multiplier | ||
1422 | * @denom: denominator portion of the ratio | ||
1423 | * @f_Ref: SRO frequency. | ||
1424 | * | ||
1425 | * This calculation handles f_ref as two separate 14-bit fields. | ||
1426 | * Therefore, a maximum value of 2^28-1 may safely be used for f_ref. | ||
1427 | * This is the genesis of the magic number "14" and the magic mask value of | ||
1428 | * 0x03FFF. | ||
1429 | * | ||
1430 | * This routine successfully handles denom values up to and including 2^18. | ||
1431 | * Returns: f_ref * num / denom | ||
1432 | */ | ||
1433 | static u32 MT2063_fLO_FractionalTerm(u32 f_ref, u32 num, u32 denom) | ||
1434 | { | ||
1435 | u32 t1 = (f_ref >> 14) * num; | ||
1436 | u32 term1 = t1 / denom; | ||
1437 | u32 loss = t1 % denom; | ||
1438 | u32 term2 = | ||
1439 | (((f_ref & 0x00003FFF) * num + (loss << 14)) + (denom / 2)) / denom; | ||
1440 | return (term1 << 14) + term2; | ||
1441 | } | ||
1442 | |||
1443 | /* | ||
1444 | * CalcLO1Mult()- Calculates Integer divider value and the numerator | ||
1445 | * value for a FracN PLL. | ||
1446 | * | ||
1447 | * This function assumes that the f_LO and f_Ref are | ||
1448 | * evenly divisible by f_LO_Step. | ||
1449 | * | ||
1450 | * @Div: OUTPUT: Whole number portion of the multiplier | ||
1451 | * @FracN: OUTPUT: Fractional portion of the multiplier | ||
1452 | * @f_LO: desired LO frequency. | ||
1453 | * @f_LO_Step: Minimum step size for the LO (in Hz). | ||
1454 | * @f_Ref: SRO frequency. | ||
1455 | * @f_Avoid: Range of PLL frequencies to avoid near integer multiples | ||
1456 | * of f_Ref (in Hz). | ||
1457 | * | ||
1458 | * Returns: Recalculated LO frequency. | ||
1459 | */ | ||
1460 | static u32 MT2063_CalcLO1Mult(u32 *Div, | ||
1461 | u32 *FracN, | ||
1462 | u32 f_LO, | ||
1463 | u32 f_LO_Step, u32 f_Ref) | ||
1464 | { | ||
1465 | /* Calculate the whole number portion of the divider */ | ||
1466 | *Div = f_LO / f_Ref; | ||
1467 | |||
1468 | /* Calculate the numerator value (round to nearest f_LO_Step) */ | ||
1469 | *FracN = | ||
1470 | (64 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) + | ||
1471 | (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step); | ||
1472 | |||
1473 | return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN, 64); | ||
1474 | } | ||
1475 | |||
1476 | /** | ||
1477 | * CalcLO2Mult() - Calculates Integer divider value and the numerator | ||
1478 | * value for a FracN PLL. | ||
1479 | * | ||
1480 | * This function assumes that the f_LO and f_Ref are | ||
1481 | * evenly divisible by f_LO_Step. | ||
1482 | * | ||
1483 | * @Div: OUTPUT: Whole number portion of the multiplier | ||
1484 | * @FracN: OUTPUT: Fractional portion of the multiplier | ||
1485 | * @f_LO: desired LO frequency. | ||
1486 | * @f_LO_Step: Minimum step size for the LO (in Hz). | ||
1487 | * @f_Ref: SRO frequency. | ||
1488 | * @f_Avoid: Range of PLL frequencies to avoid near | ||
1489 | * integer multiples of f_Ref (in Hz). | ||
1490 | * | ||
1491 | * Returns: Recalculated LO frequency. | ||
1492 | */ | ||
1493 | static u32 MT2063_CalcLO2Mult(u32 *Div, | ||
1494 | u32 *FracN, | ||
1495 | u32 f_LO, | ||
1496 | u32 f_LO_Step, u32 f_Ref) | ||
1497 | { | ||
1498 | /* Calculate the whole number portion of the divider */ | ||
1499 | *Div = f_LO / f_Ref; | ||
1500 | |||
1501 | /* Calculate the numerator value (round to nearest f_LO_Step) */ | ||
1502 | *FracN = | ||
1503 | (8191 * (((f_LO % f_Ref) + (f_LO_Step / 2)) / f_LO_Step) + | ||
1504 | (f_Ref / f_LO_Step / 2)) / (f_Ref / f_LO_Step); | ||
1505 | |||
1506 | return (f_Ref * (*Div)) + MT2063_fLO_FractionalTerm(f_Ref, *FracN, | ||
1507 | 8191); | ||
1508 | } | ||
1509 | |||
1510 | /* | ||
1511 | * FindClearTuneFilter() - Calculate the corrrect ClearTune filter to be | ||
1512 | * used for a given input frequency. | ||
1513 | * | ||
1514 | * @state: ptr to tuner data structure | ||
1515 | * @f_in: RF input center frequency (in Hz). | ||
1516 | * | ||
1517 | * Returns: ClearTune filter number (0-31) | ||
1518 | */ | ||
1519 | static u32 FindClearTuneFilter(struct mt2063_state *state, u32 f_in) | ||
1520 | { | ||
1521 | u32 RFBand; | ||
1522 | u32 idx; /* index loop */ | ||
1523 | |||
1524 | /* | ||
1525 | ** Find RF Band setting | ||
1526 | */ | ||
1527 | RFBand = 31; /* def when f_in > all */ | ||
1528 | for (idx = 0; idx < 31; ++idx) { | ||
1529 | if (state->CTFiltMax[idx] >= f_in) { | ||
1530 | RFBand = idx; | ||
1531 | break; | ||
1532 | } | ||
1533 | } | ||
1534 | return RFBand; | ||
1535 | } | ||
1536 | |||
1537 | /* | ||
1538 | * MT2063_Tune() - Change the tuner's tuned frequency to RFin. | ||
1539 | */ | ||
1540 | static u32 MT2063_Tune(struct mt2063_state *state, u32 f_in) | ||
1541 | { /* RF input center frequency */ | ||
1542 | |||
1543 | u32 status = 0; | ||
1544 | u32 LO1; /* 1st LO register value */ | ||
1545 | u32 Num1; /* Numerator for LO1 reg. value */ | ||
1546 | u32 f_IF1; /* 1st IF requested */ | ||
1547 | u32 LO2; /* 2nd LO register value */ | ||
1548 | u32 Num2; /* Numerator for LO2 reg. value */ | ||
1549 | u32 ofLO1, ofLO2; /* last time's LO frequencies */ | ||
1550 | u8 fiffc = 0x80; /* FIFF center freq from tuner */ | ||
1551 | u32 fiffof; /* Offset from FIFF center freq */ | ||
1552 | const u8 LO1LK = 0x80; /* Mask for LO1 Lock bit */ | ||
1553 | u8 LO2LK = 0x08; /* Mask for LO2 Lock bit */ | ||
1554 | u8 val; | ||
1555 | u32 RFBand; | ||
1556 | |||
1557 | dprintk(2, "\n"); | ||
1558 | /* Check the input and output frequency ranges */ | ||
1559 | if ((f_in < MT2063_MIN_FIN_FREQ) || (f_in > MT2063_MAX_FIN_FREQ)) | ||
1560 | return -EINVAL; | ||
1561 | |||
1562 | if ((state->AS_Data.f_out < MT2063_MIN_FOUT_FREQ) | ||
1563 | || (state->AS_Data.f_out > MT2063_MAX_FOUT_FREQ)) | ||
1564 | return -EINVAL; | ||
1565 | |||
1566 | /* | ||
1567 | * Save original LO1 and LO2 register values | ||
1568 | */ | ||
1569 | ofLO1 = state->AS_Data.f_LO1; | ||
1570 | ofLO2 = state->AS_Data.f_LO2; | ||
1571 | |||
1572 | /* | ||
1573 | * Find and set RF Band setting | ||
1574 | */ | ||
1575 | if (state->ctfilt_sw == 1) { | ||
1576 | val = (state->reg[MT2063_REG_CTUNE_CTRL] | 0x08); | ||
1577 | if (state->reg[MT2063_REG_CTUNE_CTRL] != val) { | ||
1578 | status |= | ||
1579 | mt2063_setreg(state, MT2063_REG_CTUNE_CTRL, val); | ||
1580 | } | ||
1581 | val = state->reg[MT2063_REG_CTUNE_OV]; | ||
1582 | RFBand = FindClearTuneFilter(state, f_in); | ||
1583 | state->reg[MT2063_REG_CTUNE_OV] = | ||
1584 | (u8) ((state->reg[MT2063_REG_CTUNE_OV] & ~0x1F) | ||
1585 | | RFBand); | ||
1586 | if (state->reg[MT2063_REG_CTUNE_OV] != val) { | ||
1587 | status |= | ||
1588 | mt2063_setreg(state, MT2063_REG_CTUNE_OV, val); | ||
1589 | } | ||
1590 | } | ||
1591 | |||
1592 | /* | ||
1593 | * Read the FIFF Center Frequency from the tuner | ||
1594 | */ | ||
1595 | if (status >= 0) { | ||
1596 | status |= | ||
1597 | mt2063_read(state, | ||
1598 | MT2063_REG_FIFFC, | ||
1599 | &state->reg[MT2063_REG_FIFFC], 1); | ||
1600 | fiffc = state->reg[MT2063_REG_FIFFC]; | ||
1601 | } | ||
1602 | /* | ||
1603 | * Assign in the requested values | ||
1604 | */ | ||
1605 | state->AS_Data.f_in = f_in; | ||
1606 | /* Request a 1st IF such that LO1 is on a step size */ | ||
1607 | state->AS_Data.f_if1_Request = | ||
1608 | MT2063_Round_fLO(state->AS_Data.f_if1_Request + f_in, | ||
1609 | state->AS_Data.f_LO1_Step, | ||
1610 | state->AS_Data.f_ref) - f_in; | ||
1611 | |||
1612 | /* | ||
1613 | * Calculate frequency settings. f_IF1_FREQ + f_in is the | ||
1614 | * desired LO1 frequency | ||
1615 | */ | ||
1616 | MT2063_ResetExclZones(&state->AS_Data); | ||
1617 | |||
1618 | f_IF1 = MT2063_ChooseFirstIF(&state->AS_Data); | ||
1619 | |||
1620 | state->AS_Data.f_LO1 = | ||
1621 | MT2063_Round_fLO(f_IF1 + f_in, state->AS_Data.f_LO1_Step, | ||
1622 | state->AS_Data.f_ref); | ||
1623 | |||
1624 | state->AS_Data.f_LO2 = | ||
1625 | MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in, | ||
1626 | state->AS_Data.f_LO2_Step, state->AS_Data.f_ref); | ||
1627 | |||
1628 | /* | ||
1629 | * Check for any LO spurs in the output bandwidth and adjust | ||
1630 | * the LO settings to avoid them if needed | ||
1631 | */ | ||
1632 | status |= MT2063_AvoidSpurs(&state->AS_Data); | ||
1633 | /* | ||
1634 | * MT_AvoidSpurs spurs may have changed the LO1 & LO2 values. | ||
1635 | * Recalculate the LO frequencies and the values to be placed | ||
1636 | * in the tuning registers. | ||
1637 | */ | ||
1638 | state->AS_Data.f_LO1 = | ||
1639 | MT2063_CalcLO1Mult(&LO1, &Num1, state->AS_Data.f_LO1, | ||
1640 | state->AS_Data.f_LO1_Step, state->AS_Data.f_ref); | ||
1641 | state->AS_Data.f_LO2 = | ||
1642 | MT2063_Round_fLO(state->AS_Data.f_LO1 - state->AS_Data.f_out - f_in, | ||
1643 | state->AS_Data.f_LO2_Step, state->AS_Data.f_ref); | ||
1644 | state->AS_Data.f_LO2 = | ||
1645 | MT2063_CalcLO2Mult(&LO2, &Num2, state->AS_Data.f_LO2, | ||
1646 | state->AS_Data.f_LO2_Step, state->AS_Data.f_ref); | ||
1647 | |||
1648 | /* | ||
1649 | * Check the upconverter and downconverter frequency ranges | ||
1650 | */ | ||
1651 | if ((state->AS_Data.f_LO1 < MT2063_MIN_UPC_FREQ) | ||
1652 | || (state->AS_Data.f_LO1 > MT2063_MAX_UPC_FREQ)) | ||
1653 | status |= MT2063_UPC_RANGE; | ||
1654 | if ((state->AS_Data.f_LO2 < MT2063_MIN_DNC_FREQ) | ||
1655 | || (state->AS_Data.f_LO2 > MT2063_MAX_DNC_FREQ)) | ||
1656 | status |= MT2063_DNC_RANGE; | ||
1657 | /* LO2 Lock bit was in a different place for B0 version */ | ||
1658 | if (state->tuner_id == MT2063_B0) | ||
1659 | LO2LK = 0x40; | ||
1660 | |||
1661 | /* | ||
1662 | * If we have the same LO frequencies and we're already locked, | ||
1663 | * then skip re-programming the LO registers. | ||
1664 | */ | ||
1665 | if ((ofLO1 != state->AS_Data.f_LO1) | ||
1666 | || (ofLO2 != state->AS_Data.f_LO2) | ||
1667 | || ((state->reg[MT2063_REG_LO_STATUS] & (LO1LK | LO2LK)) != | ||
1668 | (LO1LK | LO2LK))) { | ||
1669 | /* | ||
1670 | * Calculate the FIFFOF register value | ||
1671 | * | ||
1672 | * IF1_Actual | ||
1673 | * FIFFOF = ------------ - 8 * FIFFC - 4992 | ||
1674 | * f_ref/64 | ||
1675 | */ | ||
1676 | fiffof = | ||
1677 | (state->AS_Data.f_LO1 - | ||
1678 | f_in) / (state->AS_Data.f_ref / 64) - 8 * (u32) fiffc - | ||
1679 | 4992; | ||
1680 | if (fiffof > 0xFF) | ||
1681 | fiffof = 0xFF; | ||
1682 | |||
1683 | /* | ||
1684 | * Place all of the calculated values into the local tuner | ||
1685 | * register fields. | ||
1686 | */ | ||
1687 | if (status >= 0) { | ||
1688 | state->reg[MT2063_REG_LO1CQ_1] = (u8) (LO1 & 0xFF); /* DIV1q */ | ||
1689 | state->reg[MT2063_REG_LO1CQ_2] = (u8) (Num1 & 0x3F); /* NUM1q */ | ||
1690 | state->reg[MT2063_REG_LO2CQ_1] = (u8) (((LO2 & 0x7F) << 1) /* DIV2q */ | ||
1691 | |(Num2 >> 12)); /* NUM2q (hi) */ | ||
1692 | state->reg[MT2063_REG_LO2CQ_2] = (u8) ((Num2 & 0x0FF0) >> 4); /* NUM2q (mid) */ | ||
1693 | state->reg[MT2063_REG_LO2CQ_3] = (u8) (0xE0 | (Num2 & 0x000F)); /* NUM2q (lo) */ | ||
1694 | |||
1695 | /* | ||
1696 | * Now write out the computed register values | ||
1697 | * IMPORTANT: There is a required order for writing | ||
1698 | * (0x05 must follow all the others). | ||
1699 | */ | ||
1700 | status |= mt2063_write(state, MT2063_REG_LO1CQ_1, &state->reg[MT2063_REG_LO1CQ_1], 5); /* 0x01 - 0x05 */ | ||
1701 | if (state->tuner_id == MT2063_B0) { | ||
1702 | /* Re-write the one-shot bits to trigger the tune operation */ | ||
1703 | status |= mt2063_write(state, MT2063_REG_LO2CQ_3, &state->reg[MT2063_REG_LO2CQ_3], 1); /* 0x05 */ | ||
1704 | } | ||
1705 | /* Write out the FIFF offset only if it's changing */ | ||
1706 | if (state->reg[MT2063_REG_FIFF_OFFSET] != | ||
1707 | (u8) fiffof) { | ||
1708 | state->reg[MT2063_REG_FIFF_OFFSET] = | ||
1709 | (u8) fiffof; | ||
1710 | status |= | ||
1711 | mt2063_write(state, | ||
1712 | MT2063_REG_FIFF_OFFSET, | ||
1713 | &state-> | ||
1714 | reg[MT2063_REG_FIFF_OFFSET], | ||
1715 | 1); | ||
1716 | } | ||
1717 | } | ||
1718 | |||
1719 | /* | ||
1720 | * Check for LO's locking | ||
1721 | */ | ||
1722 | |||
1723 | if (status < 0) | ||
1724 | return status; | ||
1725 | |||
1726 | status = mt2063_lockStatus(state); | ||
1727 | if (status < 0) | ||
1728 | return status; | ||
1729 | if (!status) | ||
1730 | return -EINVAL; /* Couldn't lock */ | ||
1731 | |||
1732 | /* | ||
1733 | * If we locked OK, assign calculated data to mt2063_state structure | ||
1734 | */ | ||
1735 | state->f_IF1_actual = state->AS_Data.f_LO1 - f_in; | ||
1736 | } | ||
1737 | |||
1738 | return status; | ||
1739 | } | ||
1740 | |||
1741 | static const u8 MT2063B0_defaults[] = { | ||
1742 | /* Reg, Value */ | ||
1743 | 0x19, 0x05, | ||
1744 | 0x1B, 0x1D, | ||
1745 | 0x1C, 0x1F, | ||
1746 | 0x1D, 0x0F, | ||
1747 | 0x1E, 0x3F, | ||
1748 | 0x1F, 0x0F, | ||
1749 | 0x20, 0x3F, | ||
1750 | 0x22, 0x21, | ||
1751 | 0x23, 0x3F, | ||
1752 | 0x24, 0x20, | ||
1753 | 0x25, 0x3F, | ||
1754 | 0x27, 0xEE, | ||
1755 | 0x2C, 0x27, /* bit at 0x20 is cleared below */ | ||
1756 | 0x30, 0x03, | ||
1757 | 0x2C, 0x07, /* bit at 0x20 is cleared here */ | ||
1758 | 0x2D, 0x87, | ||
1759 | 0x2E, 0xAA, | ||
1760 | 0x28, 0xE1, /* Set the FIFCrst bit here */ | ||
1761 | 0x28, 0xE0, /* Clear the FIFCrst bit here */ | ||
1762 | 0x00 | ||
1763 | }; | ||
1764 | |||
1765 | /* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */ | ||
1766 | static const u8 MT2063B1_defaults[] = { | ||
1767 | /* Reg, Value */ | ||
1768 | 0x05, 0xF0, | ||
1769 | 0x11, 0x10, /* New Enable AFCsd */ | ||
1770 | 0x19, 0x05, | ||
1771 | 0x1A, 0x6C, | ||
1772 | 0x1B, 0x24, | ||
1773 | 0x1C, 0x28, | ||
1774 | 0x1D, 0x8F, | ||
1775 | 0x1E, 0x14, | ||
1776 | 0x1F, 0x8F, | ||
1777 | 0x20, 0x57, | ||
1778 | 0x22, 0x21, /* New - ver 1.03 */ | ||
1779 | 0x23, 0x3C, /* New - ver 1.10 */ | ||
1780 | 0x24, 0x20, /* New - ver 1.03 */ | ||
1781 | 0x2C, 0x24, /* bit at 0x20 is cleared below */ | ||
1782 | 0x2D, 0x87, /* FIFFQ=0 */ | ||
1783 | 0x2F, 0xF3, | ||
1784 | 0x30, 0x0C, /* New - ver 1.11 */ | ||
1785 | 0x31, 0x1B, /* New - ver 1.11 */ | ||
1786 | 0x2C, 0x04, /* bit at 0x20 is cleared here */ | ||
1787 | 0x28, 0xE1, /* Set the FIFCrst bit here */ | ||
1788 | 0x28, 0xE0, /* Clear the FIFCrst bit here */ | ||
1789 | 0x00 | ||
1790 | }; | ||
1791 | |||
1792 | /* writing 0x05 0xf0 sw-resets all registers, so we write only needed changes */ | ||
1793 | static const u8 MT2063B3_defaults[] = { | ||
1794 | /* Reg, Value */ | ||
1795 | 0x05, 0xF0, | ||
1796 | 0x19, 0x3D, | ||
1797 | 0x2C, 0x24, /* bit at 0x20 is cleared below */ | ||
1798 | 0x2C, 0x04, /* bit at 0x20 is cleared here */ | ||
1799 | 0x28, 0xE1, /* Set the FIFCrst bit here */ | ||
1800 | 0x28, 0xE0, /* Clear the FIFCrst bit here */ | ||
1801 | 0x00 | ||
1802 | }; | ||
1803 | |||
1804 | static int mt2063_init(struct dvb_frontend *fe) | ||
1805 | { | ||
1806 | u32 status; | ||
1807 | struct mt2063_state *state = fe->tuner_priv; | ||
1808 | u8 all_resets = 0xF0; /* reset/load bits */ | ||
1809 | const u8 *def = NULL; | ||
1810 | char *step; | ||
1811 | u32 FCRUN; | ||
1812 | s32 maxReads; | ||
1813 | u32 fcu_osc; | ||
1814 | u32 i; | ||
1815 | |||
1816 | dprintk(2, "\n"); | ||
1817 | |||
1818 | state->rcvr_mode = MT2063_CABLE_QAM; | ||
1819 | |||
1820 | /* Read the Part/Rev code from the tuner */ | ||
1821 | status = mt2063_read(state, MT2063_REG_PART_REV, | ||
1822 | &state->reg[MT2063_REG_PART_REV], 1); | ||
1823 | if (status < 0) { | ||
1824 | printk(KERN_ERR "Can't read mt2063 part ID\n"); | ||
1825 | return status; | ||
1826 | } | ||
1827 | |||
1828 | /* Check the part/rev code */ | ||
1829 | switch (state->reg[MT2063_REG_PART_REV]) { | ||
1830 | case MT2063_B0: | ||
1831 | step = "B0"; | ||
1832 | break; | ||
1833 | case MT2063_B1: | ||
1834 | step = "B1"; | ||
1835 | break; | ||
1836 | case MT2063_B2: | ||
1837 | step = "B2"; | ||
1838 | break; | ||
1839 | case MT2063_B3: | ||
1840 | step = "B3"; | ||
1841 | break; | ||
1842 | default: | ||
1843 | printk(KERN_ERR "mt2063: Unknown mt2063 device ID (0x%02x)\n", | ||
1844 | state->reg[MT2063_REG_PART_REV]); | ||
1845 | return -ENODEV; /* Wrong tuner Part/Rev code */ | ||
1846 | } | ||
1847 | |||
1848 | /* Check the 2nd byte of the Part/Rev code from the tuner */ | ||
1849 | status = mt2063_read(state, MT2063_REG_RSVD_3B, | ||
1850 | &state->reg[MT2063_REG_RSVD_3B], 1); | ||
1851 | |||
1852 | /* b7 != 0 ==> NOT MT2063 */ | ||
1853 | if (status < 0 || ((state->reg[MT2063_REG_RSVD_3B] & 0x80) != 0x00)) { | ||
1854 | printk(KERN_ERR "mt2063: Unknown part ID (0x%02x%02x)\n", | ||
1855 | state->reg[MT2063_REG_PART_REV], | ||
1856 | state->reg[MT2063_REG_RSVD_3B]); | ||
1857 | return -ENODEV; /* Wrong tuner Part/Rev code */ | ||
1858 | } | ||
1859 | |||
1860 | printk(KERN_INFO "mt2063: detected a mt2063 %s\n", step); | ||
1861 | |||
1862 | /* Reset the tuner */ | ||
1863 | status = mt2063_write(state, MT2063_REG_LO2CQ_3, &all_resets, 1); | ||
1864 | if (status < 0) | ||
1865 | return status; | ||
1866 | |||
1867 | /* change all of the default values that vary from the HW reset values */ | ||
1868 | /* def = (state->reg[PART_REV] == MT2063_B0) ? MT2063B0_defaults : MT2063B1_defaults; */ | ||
1869 | switch (state->reg[MT2063_REG_PART_REV]) { | ||
1870 | case MT2063_B3: | ||
1871 | def = MT2063B3_defaults; | ||
1872 | break; | ||
1873 | |||
1874 | case MT2063_B1: | ||
1875 | def = MT2063B1_defaults; | ||
1876 | break; | ||
1877 | |||
1878 | case MT2063_B0: | ||
1879 | def = MT2063B0_defaults; | ||
1880 | break; | ||
1881 | |||
1882 | default: | ||
1883 | return -ENODEV; | ||
1884 | break; | ||
1885 | } | ||
1886 | |||
1887 | while (status >= 0 && *def) { | ||
1888 | u8 reg = *def++; | ||
1889 | u8 val = *def++; | ||
1890 | status = mt2063_write(state, reg, &val, 1); | ||
1891 | } | ||
1892 | if (status < 0) | ||
1893 | return status; | ||
1894 | |||
1895 | /* Wait for FIFF location to complete. */ | ||
1896 | FCRUN = 1; | ||
1897 | maxReads = 10; | ||
1898 | while (status >= 0 && (FCRUN != 0) && (maxReads-- > 0)) { | ||
1899 | msleep(2); | ||
1900 | status = mt2063_read(state, | ||
1901 | MT2063_REG_XO_STATUS, | ||
1902 | &state-> | ||
1903 | reg[MT2063_REG_XO_STATUS], 1); | ||
1904 | FCRUN = (state->reg[MT2063_REG_XO_STATUS] & 0x40) >> 6; | ||
1905 | } | ||
1906 | |||
1907 | if (FCRUN != 0 || status < 0) | ||
1908 | return -ENODEV; | ||
1909 | |||
1910 | status = mt2063_read(state, | ||
1911 | MT2063_REG_FIFFC, | ||
1912 | &state->reg[MT2063_REG_FIFFC], 1); | ||
1913 | if (status < 0) | ||
1914 | return status; | ||
1915 | |||
1916 | /* Read back all the registers from the tuner */ | ||
1917 | status = mt2063_read(state, | ||
1918 | MT2063_REG_PART_REV, | ||
1919 | state->reg, MT2063_REG_END_REGS); | ||
1920 | if (status < 0) | ||
1921 | return status; | ||
1922 | |||
1923 | /* Initialize the tuner state. */ | ||
1924 | state->tuner_id = state->reg[MT2063_REG_PART_REV]; | ||
1925 | state->AS_Data.f_ref = MT2063_REF_FREQ; | ||
1926 | state->AS_Data.f_if1_Center = (state->AS_Data.f_ref / 8) * | ||
1927 | ((u32) state->reg[MT2063_REG_FIFFC] + 640); | ||
1928 | state->AS_Data.f_if1_bw = MT2063_IF1_BW; | ||
1929 | state->AS_Data.f_out = 43750000UL; | ||
1930 | state->AS_Data.f_out_bw = 6750000UL; | ||
1931 | state->AS_Data.f_zif_bw = MT2063_ZIF_BW; | ||
1932 | state->AS_Data.f_LO1_Step = state->AS_Data.f_ref / 64; | ||
1933 | state->AS_Data.f_LO2_Step = MT2063_TUNE_STEP_SIZE; | ||
1934 | state->AS_Data.maxH1 = MT2063_MAX_HARMONICS_1; | ||
1935 | state->AS_Data.maxH2 = MT2063_MAX_HARMONICS_2; | ||
1936 | state->AS_Data.f_min_LO_Separation = MT2063_MIN_LO_SEP; | ||
1937 | state->AS_Data.f_if1_Request = state->AS_Data.f_if1_Center; | ||
1938 | state->AS_Data.f_LO1 = 2181000000UL; | ||
1939 | state->AS_Data.f_LO2 = 1486249786UL; | ||
1940 | state->f_IF1_actual = state->AS_Data.f_if1_Center; | ||
1941 | state->AS_Data.f_in = state->AS_Data.f_LO1 - state->f_IF1_actual; | ||
1942 | state->AS_Data.f_LO1_FracN_Avoid = MT2063_LO1_FRACN_AVOID; | ||
1943 | state->AS_Data.f_LO2_FracN_Avoid = MT2063_LO2_FRACN_AVOID; | ||
1944 | state->num_regs = MT2063_REG_END_REGS; | ||
1945 | state->AS_Data.avoidDECT = MT2063_AVOID_BOTH; | ||
1946 | state->ctfilt_sw = 0; | ||
1947 | |||
1948 | state->CTFiltMax[0] = 69230000; | ||
1949 | state->CTFiltMax[1] = 105770000; | ||
1950 | state->CTFiltMax[2] = 140350000; | ||
1951 | state->CTFiltMax[3] = 177110000; | ||
1952 | state->CTFiltMax[4] = 212860000; | ||
1953 | state->CTFiltMax[5] = 241130000; | ||
1954 | state->CTFiltMax[6] = 274370000; | ||
1955 | state->CTFiltMax[7] = 309820000; | ||
1956 | state->CTFiltMax[8] = 342450000; | ||
1957 | state->CTFiltMax[9] = 378870000; | ||
1958 | state->CTFiltMax[10] = 416210000; | ||
1959 | state->CTFiltMax[11] = 456500000; | ||
1960 | state->CTFiltMax[12] = 495790000; | ||
1961 | state->CTFiltMax[13] = 534530000; | ||
1962 | state->CTFiltMax[14] = 572610000; | ||
1963 | state->CTFiltMax[15] = 598970000; | ||
1964 | state->CTFiltMax[16] = 635910000; | ||
1965 | state->CTFiltMax[17] = 672130000; | ||
1966 | state->CTFiltMax[18] = 714840000; | ||
1967 | state->CTFiltMax[19] = 739660000; | ||
1968 | state->CTFiltMax[20] = 770410000; | ||
1969 | state->CTFiltMax[21] = 814660000; | ||
1970 | state->CTFiltMax[22] = 846950000; | ||
1971 | state->CTFiltMax[23] = 867820000; | ||
1972 | state->CTFiltMax[24] = 915980000; | ||
1973 | state->CTFiltMax[25] = 947450000; | ||
1974 | state->CTFiltMax[26] = 983110000; | ||
1975 | state->CTFiltMax[27] = 1021630000; | ||
1976 | state->CTFiltMax[28] = 1061870000; | ||
1977 | state->CTFiltMax[29] = 1098330000; | ||
1978 | state->CTFiltMax[30] = 1138990000; | ||
1979 | |||
1980 | /* | ||
1981 | ** Fetch the FCU osc value and use it and the fRef value to | ||
1982 | ** scale all of the Band Max values | ||
1983 | */ | ||
1984 | |||
1985 | state->reg[MT2063_REG_CTUNE_CTRL] = 0x0A; | ||
1986 | status = mt2063_write(state, MT2063_REG_CTUNE_CTRL, | ||
1987 | &state->reg[MT2063_REG_CTUNE_CTRL], 1); | ||
1988 | if (status < 0) | ||
1989 | return status; | ||
1990 | |||
1991 | /* Read the ClearTune filter calibration value */ | ||
1992 | status = mt2063_read(state, MT2063_REG_FIFFC, | ||
1993 | &state->reg[MT2063_REG_FIFFC], 1); | ||
1994 | if (status < 0) | ||
1995 | return status; | ||
1996 | |||
1997 | fcu_osc = state->reg[MT2063_REG_FIFFC]; | ||
1998 | |||
1999 | state->reg[MT2063_REG_CTUNE_CTRL] = 0x00; | ||
2000 | status = mt2063_write(state, MT2063_REG_CTUNE_CTRL, | ||
2001 | &state->reg[MT2063_REG_CTUNE_CTRL], 1); | ||
2002 | if (status < 0) | ||
2003 | return status; | ||
2004 | |||
2005 | /* Adjust each of the values in the ClearTune filter cross-over table */ | ||
2006 | for (i = 0; i < 31; i++) | ||
2007 | state->CTFiltMax[i] = (state->CTFiltMax[i] / 768) * (fcu_osc + 640); | ||
2008 | |||
2009 | status = MT2063_SoftwareShutdown(state, 1); | ||
2010 | if (status < 0) | ||
2011 | return status; | ||
2012 | status = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD); | ||
2013 | if (status < 0) | ||
2014 | return status; | ||
2015 | |||
2016 | state->init = true; | ||
2017 | |||
2018 | return 0; | ||
2019 | } | ||
2020 | |||
2021 | static int mt2063_get_status(struct dvb_frontend *fe, u32 *tuner_status) | ||
2022 | { | ||
2023 | struct mt2063_state *state = fe->tuner_priv; | ||
2024 | int status; | ||
2025 | |||
2026 | dprintk(2, "\n"); | ||
2027 | |||
2028 | if (!state->init) | ||
2029 | return -ENODEV; | ||
2030 | |||
2031 | *tuner_status = 0; | ||
2032 | status = mt2063_lockStatus(state); | ||
2033 | if (status < 0) | ||
2034 | return status; | ||
2035 | if (status) | ||
2036 | *tuner_status = TUNER_STATUS_LOCKED; | ||
2037 | |||
2038 | dprintk(1, "Tuner status: %d", *tuner_status); | ||
2039 | |||
2040 | return 0; | ||
2041 | } | ||
2042 | |||
2043 | static int mt2063_release(struct dvb_frontend *fe) | ||
2044 | { | ||
2045 | struct mt2063_state *state = fe->tuner_priv; | ||
2046 | |||
2047 | dprintk(2, "\n"); | ||
2048 | |||
2049 | fe->tuner_priv = NULL; | ||
2050 | kfree(state); | ||
2051 | |||
2052 | return 0; | ||
2053 | } | ||
2054 | |||
2055 | static int mt2063_set_analog_params(struct dvb_frontend *fe, | ||
2056 | struct analog_parameters *params) | ||
2057 | { | ||
2058 | struct mt2063_state *state = fe->tuner_priv; | ||
2059 | s32 pict_car; | ||
2060 | s32 pict2chanb_vsb; | ||
2061 | s32 ch_bw; | ||
2062 | s32 if_mid; | ||
2063 | s32 rcvr_mode; | ||
2064 | int status; | ||
2065 | |||
2066 | dprintk(2, "\n"); | ||
2067 | |||
2068 | if (!state->init) { | ||
2069 | status = mt2063_init(fe); | ||
2070 | if (status < 0) | ||
2071 | return status; | ||
2072 | } | ||
2073 | |||
2074 | switch (params->mode) { | ||
2075 | case V4L2_TUNER_RADIO: | ||
2076 | pict_car = 38900000; | ||
2077 | ch_bw = 8000000; | ||
2078 | pict2chanb_vsb = -(ch_bw / 2); | ||
2079 | rcvr_mode = MT2063_OFFAIR_ANALOG; | ||
2080 | break; | ||
2081 | case V4L2_TUNER_ANALOG_TV: | ||
2082 | rcvr_mode = MT2063_CABLE_ANALOG; | ||
2083 | if (params->std & ~V4L2_STD_MN) { | ||
2084 | pict_car = 38900000; | ||
2085 | ch_bw = 6000000; | ||
2086 | pict2chanb_vsb = -1250000; | ||
2087 | } else if (params->std & V4L2_STD_PAL_G) { | ||
2088 | pict_car = 38900000; | ||
2089 | ch_bw = 7000000; | ||
2090 | pict2chanb_vsb = -1250000; | ||
2091 | } else { /* PAL/SECAM standards */ | ||
2092 | pict_car = 38900000; | ||
2093 | ch_bw = 8000000; | ||
2094 | pict2chanb_vsb = -1250000; | ||
2095 | } | ||
2096 | break; | ||
2097 | default: | ||
2098 | return -EINVAL; | ||
2099 | } | ||
2100 | if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2)); | ||
2101 | |||
2102 | state->AS_Data.f_LO2_Step = 125000; /* FIXME: probably 5000 for FM */ | ||
2103 | state->AS_Data.f_out = if_mid; | ||
2104 | state->AS_Data.f_out_bw = ch_bw + 750000; | ||
2105 | status = MT2063_SetReceiverMode(state, rcvr_mode); | ||
2106 | if (status < 0) | ||
2107 | return status; | ||
2108 | |||
2109 | dprintk(1, "Tuning to frequency: %d, bandwidth %d, foffset %d\n", | ||
2110 | params->frequency, ch_bw, pict2chanb_vsb); | ||
2111 | |||
2112 | status = MT2063_Tune(state, (params->frequency + (pict2chanb_vsb + (ch_bw / 2)))); | ||
2113 | if (status < 0) | ||
2114 | return status; | ||
2115 | |||
2116 | state->frequency = params->frequency; | ||
2117 | return 0; | ||
2118 | } | ||
2119 | |||
2120 | /* | ||
2121 | * As defined on EN 300 429, the DVB-C roll-off factor is 0.15. | ||
2122 | * So, the amount of the needed bandwith is given by: | ||
2123 | * Bw = Symbol_rate * (1 + 0.15) | ||
2124 | * As such, the maximum symbol rate supported by 6 MHz is given by: | ||
2125 | * max_symbol_rate = 6 MHz / 1.15 = 5217391 Bauds | ||
2126 | */ | ||
2127 | #define MAX_SYMBOL_RATE_6MHz 5217391 | ||
2128 | |||
2129 | static int mt2063_set_params(struct dvb_frontend *fe) | ||
2130 | { | ||
2131 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
2132 | struct mt2063_state *state = fe->tuner_priv; | ||
2133 | int status; | ||
2134 | s32 pict_car; | ||
2135 | s32 pict2chanb_vsb; | ||
2136 | s32 ch_bw; | ||
2137 | s32 if_mid; | ||
2138 | s32 rcvr_mode; | ||
2139 | |||
2140 | if (!state->init) { | ||
2141 | status = mt2063_init(fe); | ||
2142 | if (status < 0) | ||
2143 | return status; | ||
2144 | } | ||
2145 | |||
2146 | dprintk(2, "\n"); | ||
2147 | |||
2148 | if (c->bandwidth_hz == 0) | ||
2149 | return -EINVAL; | ||
2150 | if (c->bandwidth_hz <= 6000000) | ||
2151 | ch_bw = 6000000; | ||
2152 | else if (c->bandwidth_hz <= 7000000) | ||
2153 | ch_bw = 7000000; | ||
2154 | else | ||
2155 | ch_bw = 8000000; | ||
2156 | |||
2157 | switch (c->delivery_system) { | ||
2158 | case SYS_DVBT: | ||
2159 | rcvr_mode = MT2063_OFFAIR_COFDM; | ||
2160 | pict_car = 36125000; | ||
2161 | pict2chanb_vsb = -(ch_bw / 2); | ||
2162 | break; | ||
2163 | case SYS_DVBC_ANNEX_A: | ||
2164 | case SYS_DVBC_ANNEX_C: | ||
2165 | rcvr_mode = MT2063_CABLE_QAM; | ||
2166 | pict_car = 36125000; | ||
2167 | pict2chanb_vsb = -(ch_bw / 2); | ||
2168 | break; | ||
2169 | default: | ||
2170 | return -EINVAL; | ||
2171 | } | ||
2172 | if_mid = pict_car - (pict2chanb_vsb + (ch_bw / 2)); | ||
2173 | |||
2174 | state->AS_Data.f_LO2_Step = 125000; /* FIXME: probably 5000 for FM */ | ||
2175 | state->AS_Data.f_out = if_mid; | ||
2176 | state->AS_Data.f_out_bw = ch_bw + 750000; | ||
2177 | status = MT2063_SetReceiverMode(state, rcvr_mode); | ||
2178 | if (status < 0) | ||
2179 | return status; | ||
2180 | |||
2181 | dprintk(1, "Tuning to frequency: %d, bandwidth %d, foffset %d\n", | ||
2182 | c->frequency, ch_bw, pict2chanb_vsb); | ||
2183 | |||
2184 | status = MT2063_Tune(state, (c->frequency + (pict2chanb_vsb + (ch_bw / 2)))); | ||
2185 | |||
2186 | if (status < 0) | ||
2187 | return status; | ||
2188 | |||
2189 | state->frequency = c->frequency; | ||
2190 | return 0; | ||
2191 | } | ||
2192 | |||
2193 | static int mt2063_get_if_frequency(struct dvb_frontend *fe, u32 *freq) | ||
2194 | { | ||
2195 | struct mt2063_state *state = fe->tuner_priv; | ||
2196 | |||
2197 | dprintk(2, "\n"); | ||
2198 | |||
2199 | if (!state->init) | ||
2200 | return -ENODEV; | ||
2201 | |||
2202 | *freq = state->AS_Data.f_out; | ||
2203 | |||
2204 | dprintk(1, "IF frequency: %d\n", *freq); | ||
2205 | |||
2206 | return 0; | ||
2207 | } | ||
2208 | |||
2209 | static int mt2063_get_bandwidth(struct dvb_frontend *fe, u32 *bw) | ||
2210 | { | ||
2211 | struct mt2063_state *state = fe->tuner_priv; | ||
2212 | |||
2213 | dprintk(2, "\n"); | ||
2214 | |||
2215 | if (!state->init) | ||
2216 | return -ENODEV; | ||
2217 | |||
2218 | *bw = state->AS_Data.f_out_bw - 750000; | ||
2219 | |||
2220 | dprintk(1, "bandwidth: %d\n", *bw); | ||
2221 | |||
2222 | return 0; | ||
2223 | } | ||
2224 | |||
2225 | static struct dvb_tuner_ops mt2063_ops = { | ||
2226 | .info = { | ||
2227 | .name = "MT2063 Silicon Tuner", | ||
2228 | .frequency_min = 45000000, | ||
2229 | .frequency_max = 865000000, | ||
2230 | .frequency_step = 0, | ||
2231 | }, | ||
2232 | |||
2233 | .init = mt2063_init, | ||
2234 | .sleep = MT2063_Sleep, | ||
2235 | .get_status = mt2063_get_status, | ||
2236 | .set_analog_params = mt2063_set_analog_params, | ||
2237 | .set_params = mt2063_set_params, | ||
2238 | .get_if_frequency = mt2063_get_if_frequency, | ||
2239 | .get_bandwidth = mt2063_get_bandwidth, | ||
2240 | .release = mt2063_release, | ||
2241 | }; | ||
2242 | |||
2243 | struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe, | ||
2244 | struct mt2063_config *config, | ||
2245 | struct i2c_adapter *i2c) | ||
2246 | { | ||
2247 | struct mt2063_state *state = NULL; | ||
2248 | |||
2249 | dprintk(2, "\n"); | ||
2250 | |||
2251 | state = kzalloc(sizeof(struct mt2063_state), GFP_KERNEL); | ||
2252 | if (state == NULL) | ||
2253 | goto error; | ||
2254 | |||
2255 | state->config = config; | ||
2256 | state->i2c = i2c; | ||
2257 | state->frontend = fe; | ||
2258 | state->reference = config->refclock / 1000; /* kHz */ | ||
2259 | fe->tuner_priv = state; | ||
2260 | fe->ops.tuner_ops = mt2063_ops; | ||
2261 | |||
2262 | printk(KERN_INFO "%s: Attaching MT2063\n", __func__); | ||
2263 | return fe; | ||
2264 | |||
2265 | error: | ||
2266 | kfree(state); | ||
2267 | return NULL; | ||
2268 | } | ||
2269 | EXPORT_SYMBOL_GPL(mt2063_attach); | ||
2270 | |||
2271 | /* | ||
2272 | * Ancillary routines visible outside mt2063 | ||
2273 | * FIXME: Remove them in favor of using standard tuner callbacks | ||
2274 | */ | ||
2275 | unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe) | ||
2276 | { | ||
2277 | struct mt2063_state *state = fe->tuner_priv; | ||
2278 | int err = 0; | ||
2279 | |||
2280 | dprintk(2, "\n"); | ||
2281 | |||
2282 | err = MT2063_SoftwareShutdown(state, 1); | ||
2283 | if (err < 0) | ||
2284 | printk(KERN_ERR "%s: Couldn't shutdown\n", __func__); | ||
2285 | |||
2286 | return err; | ||
2287 | } | ||
2288 | EXPORT_SYMBOL_GPL(tuner_MT2063_SoftwareShutdown); | ||
2289 | |||
2290 | unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe) | ||
2291 | { | ||
2292 | struct mt2063_state *state = fe->tuner_priv; | ||
2293 | int err = 0; | ||
2294 | |||
2295 | dprintk(2, "\n"); | ||
2296 | |||
2297 | err = MT2063_ClearPowerMaskBits(state, MT2063_ALL_SD); | ||
2298 | if (err < 0) | ||
2299 | printk(KERN_ERR "%s: Invalid parameter\n", __func__); | ||
2300 | |||
2301 | return err; | ||
2302 | } | ||
2303 | EXPORT_SYMBOL_GPL(tuner_MT2063_ClearPowerMaskBits); | ||
2304 | |||
2305 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); | ||
2306 | MODULE_DESCRIPTION("MT2063 Silicon tuner"); | ||
2307 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/tuners/mt2063.h b/drivers/media/tuners/mt2063.h new file mode 100644 index 000000000000..3f5cfd93713f --- /dev/null +++ b/drivers/media/tuners/mt2063.h | |||
@@ -0,0 +1,32 @@ | |||
1 | #ifndef __MT2063_H__ | ||
2 | #define __MT2063_H__ | ||
3 | |||
4 | #include "dvb_frontend.h" | ||
5 | |||
6 | struct mt2063_config { | ||
7 | u8 tuner_address; | ||
8 | u32 refclock; | ||
9 | }; | ||
10 | |||
11 | #if defined(CONFIG_MEDIA_TUNER_MT2063) || (defined(CONFIG_MEDIA_TUNER_MT2063_MODULE) && defined(MODULE)) | ||
12 | struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe, | ||
13 | struct mt2063_config *config, | ||
14 | struct i2c_adapter *i2c); | ||
15 | |||
16 | #else | ||
17 | |||
18 | static inline struct dvb_frontend *mt2063_attach(struct dvb_frontend *fe, | ||
19 | struct mt2063_config *config, | ||
20 | struct i2c_adapter *i2c) | ||
21 | { | ||
22 | printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__); | ||
23 | return NULL; | ||
24 | } | ||
25 | |||
26 | /* FIXME: Should use the standard DVB attachment interfaces */ | ||
27 | unsigned int tuner_MT2063_SoftwareShutdown(struct dvb_frontend *fe); | ||
28 | unsigned int tuner_MT2063_ClearPowerMaskBits(struct dvb_frontend *fe); | ||
29 | |||
30 | #endif /* CONFIG_DVB_MT2063 */ | ||
31 | |||
32 | #endif /* __MT2063_H__ */ | ||
diff --git a/drivers/media/tuners/mt20xx.c b/drivers/media/tuners/mt20xx.c new file mode 100644 index 000000000000..0e74e97e0d1a --- /dev/null +++ b/drivers/media/tuners/mt20xx.c | |||
@@ -0,0 +1,670 @@ | |||
1 | /* | ||
2 | * i2c tv tuner chip device driver | ||
3 | * controls microtune tuners, mt2032 + mt2050 at the moment. | ||
4 | * | ||
5 | * This "mt20xx" module was split apart from the original "tuner" module. | ||
6 | */ | ||
7 | #include <linux/delay.h> | ||
8 | #include <linux/i2c.h> | ||
9 | #include <linux/slab.h> | ||
10 | #include <linux/videodev2.h> | ||
11 | #include "tuner-i2c.h" | ||
12 | #include "mt20xx.h" | ||
13 | |||
14 | static int debug; | ||
15 | module_param(debug, int, 0644); | ||
16 | MODULE_PARM_DESC(debug, "enable verbose debug messages"); | ||
17 | |||
18 | /* ---------------------------------------------------------------------- */ | ||
19 | |||
20 | static unsigned int optimize_vco = 1; | ||
21 | module_param(optimize_vco, int, 0644); | ||
22 | |||
23 | static unsigned int tv_antenna = 1; | ||
24 | module_param(tv_antenna, int, 0644); | ||
25 | |||
26 | static unsigned int radio_antenna; | ||
27 | module_param(radio_antenna, int, 0644); | ||
28 | |||
29 | /* ---------------------------------------------------------------------- */ | ||
30 | |||
31 | #define MT2032 0x04 | ||
32 | #define MT2030 0x06 | ||
33 | #define MT2040 0x07 | ||
34 | #define MT2050 0x42 | ||
35 | |||
36 | static char *microtune_part[] = { | ||
37 | [ MT2030 ] = "MT2030", | ||
38 | [ MT2032 ] = "MT2032", | ||
39 | [ MT2040 ] = "MT2040", | ||
40 | [ MT2050 ] = "MT2050", | ||
41 | }; | ||
42 | |||
43 | struct microtune_priv { | ||
44 | struct tuner_i2c_props i2c_props; | ||
45 | |||
46 | unsigned int xogc; | ||
47 | //unsigned int radio_if2; | ||
48 | |||
49 | u32 frequency; | ||
50 | }; | ||
51 | |||
52 | static int microtune_release(struct dvb_frontend *fe) | ||
53 | { | ||
54 | kfree(fe->tuner_priv); | ||
55 | fe->tuner_priv = NULL; | ||
56 | |||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | static int microtune_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
61 | { | ||
62 | struct microtune_priv *priv = fe->tuner_priv; | ||
63 | *frequency = priv->frequency; | ||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | // IsSpurInBand()? | ||
68 | static int mt2032_spurcheck(struct dvb_frontend *fe, | ||
69 | int f1, int f2, int spectrum_from,int spectrum_to) | ||
70 | { | ||
71 | struct microtune_priv *priv = fe->tuner_priv; | ||
72 | int n1=1,n2,f; | ||
73 | |||
74 | f1=f1/1000; //scale to kHz to avoid 32bit overflows | ||
75 | f2=f2/1000; | ||
76 | spectrum_from/=1000; | ||
77 | spectrum_to/=1000; | ||
78 | |||
79 | tuner_dbg("spurcheck f1=%d f2=%d from=%d to=%d\n", | ||
80 | f1,f2,spectrum_from,spectrum_to); | ||
81 | |||
82 | do { | ||
83 | n2=-n1; | ||
84 | f=n1*(f1-f2); | ||
85 | do { | ||
86 | n2--; | ||
87 | f=f-f2; | ||
88 | tuner_dbg("spurtest n1=%d n2=%d ftest=%d\n",n1,n2,f); | ||
89 | |||
90 | if( (f>spectrum_from) && (f<spectrum_to)) | ||
91 | tuner_dbg("mt2032 spurcheck triggered: %d\n",n1); | ||
92 | } while ( (f>(f2-spectrum_to)) || (n2>-5)); | ||
93 | n1++; | ||
94 | } while (n1<5); | ||
95 | |||
96 | return 1; | ||
97 | } | ||
98 | |||
99 | static int mt2032_compute_freq(struct dvb_frontend *fe, | ||
100 | unsigned int rfin, | ||
101 | unsigned int if1, unsigned int if2, | ||
102 | unsigned int spectrum_from, | ||
103 | unsigned int spectrum_to, | ||
104 | unsigned char *buf, | ||
105 | int *ret_sel, | ||
106 | unsigned int xogc) //all in Hz | ||
107 | { | ||
108 | struct microtune_priv *priv = fe->tuner_priv; | ||
109 | unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1, | ||
110 | desired_lo2,lo2,lo2n,lo2a,lo2num,lo2freq; | ||
111 | |||
112 | fref= 5250 *1000; //5.25MHz | ||
113 | desired_lo1=rfin+if1; | ||
114 | |||
115 | lo1=(2*(desired_lo1/1000)+(fref/1000)) / (2*fref/1000); | ||
116 | lo1n=lo1/8; | ||
117 | lo1a=lo1-(lo1n*8); | ||
118 | |||
119 | s=rfin/1000/1000+1090; | ||
120 | |||
121 | if(optimize_vco) { | ||
122 | if(s>1890) sel=0; | ||
123 | else if(s>1720) sel=1; | ||
124 | else if(s>1530) sel=2; | ||
125 | else if(s>1370) sel=3; | ||
126 | else sel=4; // >1090 | ||
127 | } | ||
128 | else { | ||
129 | if(s>1790) sel=0; // <1958 | ||
130 | else if(s>1617) sel=1; | ||
131 | else if(s>1449) sel=2; | ||
132 | else if(s>1291) sel=3; | ||
133 | else sel=4; // >1090 | ||
134 | } | ||
135 | *ret_sel=sel; | ||
136 | |||
137 | lo1freq=(lo1a+8*lo1n)*fref; | ||
138 | |||
139 | tuner_dbg("mt2032: rfin=%d lo1=%d lo1n=%d lo1a=%d sel=%d, lo1freq=%d\n", | ||
140 | rfin,lo1,lo1n,lo1a,sel,lo1freq); | ||
141 | |||
142 | desired_lo2=lo1freq-rfin-if2; | ||
143 | lo2=(desired_lo2)/fref; | ||
144 | lo2n=lo2/8; | ||
145 | lo2a=lo2-(lo2n*8); | ||
146 | lo2num=((desired_lo2/1000)%(fref/1000))* 3780/(fref/1000); //scale to fit in 32bit arith | ||
147 | lo2freq=(lo2a+8*lo2n)*fref + lo2num*(fref/1000)/3780*1000; | ||
148 | |||
149 | tuner_dbg("mt2032: rfin=%d lo2=%d lo2n=%d lo2a=%d num=%d lo2freq=%d\n", | ||
150 | rfin,lo2,lo2n,lo2a,lo2num,lo2freq); | ||
151 | |||
152 | if (lo1a > 7 || lo1n < 17 || lo1n > 48 || lo2a > 7 || lo2n < 17 || | ||
153 | lo2n > 30) { | ||
154 | tuner_info("mt2032: frequency parameters out of range: %d %d %d %d\n", | ||
155 | lo1a, lo1n, lo2a,lo2n); | ||
156 | return(-1); | ||
157 | } | ||
158 | |||
159 | mt2032_spurcheck(fe, lo1freq, desired_lo2, spectrum_from, spectrum_to); | ||
160 | // should recalculate lo1 (one step up/down) | ||
161 | |||
162 | // set up MT2032 register map for transfer over i2c | ||
163 | buf[0]=lo1n-1; | ||
164 | buf[1]=lo1a | (sel<<4); | ||
165 | buf[2]=0x86; // LOGC | ||
166 | buf[3]=0x0f; //reserved | ||
167 | buf[4]=0x1f; | ||
168 | buf[5]=(lo2n-1) | (lo2a<<5); | ||
169 | if(rfin >400*1000*1000) | ||
170 | buf[6]=0xe4; | ||
171 | else | ||
172 | buf[6]=0xf4; // set PKEN per rev 1.2 | ||
173 | buf[7]=8+xogc; | ||
174 | buf[8]=0xc3; //reserved | ||
175 | buf[9]=0x4e; //reserved | ||
176 | buf[10]=0xec; //reserved | ||
177 | buf[11]=(lo2num&0xff); | ||
178 | buf[12]=(lo2num>>8) |0x80; // Lo2RST | ||
179 | |||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | static int mt2032_check_lo_lock(struct dvb_frontend *fe) | ||
184 | { | ||
185 | struct microtune_priv *priv = fe->tuner_priv; | ||
186 | int try,lock=0; | ||
187 | unsigned char buf[2]; | ||
188 | |||
189 | for(try=0;try<10;try++) { | ||
190 | buf[0]=0x0e; | ||
191 | tuner_i2c_xfer_send(&priv->i2c_props,buf,1); | ||
192 | tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); | ||
193 | tuner_dbg("mt2032 Reg.E=0x%02x\n",buf[0]); | ||
194 | lock=buf[0] &0x06; | ||
195 | |||
196 | if (lock==6) | ||
197 | break; | ||
198 | |||
199 | tuner_dbg("mt2032: pll wait 1ms for lock (0x%2x)\n",buf[0]); | ||
200 | udelay(1000); | ||
201 | } | ||
202 | return lock; | ||
203 | } | ||
204 | |||
205 | static int mt2032_optimize_vco(struct dvb_frontend *fe,int sel,int lock) | ||
206 | { | ||
207 | struct microtune_priv *priv = fe->tuner_priv; | ||
208 | unsigned char buf[2]; | ||
209 | int tad1; | ||
210 | |||
211 | buf[0]=0x0f; | ||
212 | tuner_i2c_xfer_send(&priv->i2c_props,buf,1); | ||
213 | tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); | ||
214 | tuner_dbg("mt2032 Reg.F=0x%02x\n",buf[0]); | ||
215 | tad1=buf[0]&0x07; | ||
216 | |||
217 | if(tad1 ==0) return lock; | ||
218 | if(tad1 ==1) return lock; | ||
219 | |||
220 | if(tad1==2) { | ||
221 | if(sel==0) | ||
222 | return lock; | ||
223 | else sel--; | ||
224 | } | ||
225 | else { | ||
226 | if(sel<4) | ||
227 | sel++; | ||
228 | else | ||
229 | return lock; | ||
230 | } | ||
231 | |||
232 | tuner_dbg("mt2032 optimize_vco: sel=%d\n",sel); | ||
233 | |||
234 | buf[0]=0x0f; | ||
235 | buf[1]=sel; | ||
236 | tuner_i2c_xfer_send(&priv->i2c_props,buf,2); | ||
237 | lock=mt2032_check_lo_lock(fe); | ||
238 | return lock; | ||
239 | } | ||
240 | |||
241 | |||
242 | static void mt2032_set_if_freq(struct dvb_frontend *fe, unsigned int rfin, | ||
243 | unsigned int if1, unsigned int if2, | ||
244 | unsigned int from, unsigned int to) | ||
245 | { | ||
246 | unsigned char buf[21]; | ||
247 | int lint_try,ret,sel,lock=0; | ||
248 | struct microtune_priv *priv = fe->tuner_priv; | ||
249 | |||
250 | tuner_dbg("mt2032_set_if_freq rfin=%d if1=%d if2=%d from=%d to=%d\n", | ||
251 | rfin,if1,if2,from,to); | ||
252 | |||
253 | buf[0]=0; | ||
254 | ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,1); | ||
255 | tuner_i2c_xfer_recv(&priv->i2c_props,buf,21); | ||
256 | |||
257 | buf[0]=0; | ||
258 | ret=mt2032_compute_freq(fe,rfin,if1,if2,from,to,&buf[1],&sel,priv->xogc); | ||
259 | if (ret<0) | ||
260 | return; | ||
261 | |||
262 | // send only the relevant registers per Rev. 1.2 | ||
263 | buf[0]=0; | ||
264 | ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,4); | ||
265 | buf[5]=5; | ||
266 | ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+5,4); | ||
267 | buf[11]=11; | ||
268 | ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+11,3); | ||
269 | if(ret!=3) | ||
270 | tuner_warn("i2c i/o error: rc == %d (should be 3)\n",ret); | ||
271 | |||
272 | // wait for PLLs to lock (per manual), retry LINT if not. | ||
273 | for(lint_try=0; lint_try<2; lint_try++) { | ||
274 | lock=mt2032_check_lo_lock(fe); | ||
275 | |||
276 | if(optimize_vco) | ||
277 | lock=mt2032_optimize_vco(fe,sel,lock); | ||
278 | if(lock==6) break; | ||
279 | |||
280 | tuner_dbg("mt2032: re-init PLLs by LINT\n"); | ||
281 | buf[0]=7; | ||
282 | buf[1]=0x80 +8+priv->xogc; // set LINT to re-init PLLs | ||
283 | tuner_i2c_xfer_send(&priv->i2c_props,buf,2); | ||
284 | mdelay(10); | ||
285 | buf[1]=8+priv->xogc; | ||
286 | tuner_i2c_xfer_send(&priv->i2c_props,buf,2); | ||
287 | } | ||
288 | |||
289 | if (lock!=6) | ||
290 | tuner_warn("MT2032 Fatal Error: PLLs didn't lock.\n"); | ||
291 | |||
292 | buf[0]=2; | ||
293 | buf[1]=0x20; // LOGC for optimal phase noise | ||
294 | ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); | ||
295 | if (ret!=2) | ||
296 | tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret); | ||
297 | } | ||
298 | |||
299 | |||
300 | static int mt2032_set_tv_freq(struct dvb_frontend *fe, | ||
301 | struct analog_parameters *params) | ||
302 | { | ||
303 | int if2,from,to; | ||
304 | |||
305 | // signal bandwidth and picture carrier | ||
306 | if (params->std & V4L2_STD_525_60) { | ||
307 | // NTSC | ||
308 | from = 40750*1000; | ||
309 | to = 46750*1000; | ||
310 | if2 = 45750*1000; | ||
311 | } else { | ||
312 | // PAL | ||
313 | from = 32900*1000; | ||
314 | to = 39900*1000; | ||
315 | if2 = 38900*1000; | ||
316 | } | ||
317 | |||
318 | mt2032_set_if_freq(fe, params->frequency*62500, | ||
319 | 1090*1000*1000, if2, from, to); | ||
320 | |||
321 | return 0; | ||
322 | } | ||
323 | |||
324 | static int mt2032_set_radio_freq(struct dvb_frontend *fe, | ||
325 | struct analog_parameters *params) | ||
326 | { | ||
327 | struct microtune_priv *priv = fe->tuner_priv; | ||
328 | int if2; | ||
329 | |||
330 | if (params->std & V4L2_STD_525_60) { | ||
331 | tuner_dbg("pinnacle ntsc\n"); | ||
332 | if2 = 41300 * 1000; | ||
333 | } else { | ||
334 | tuner_dbg("pinnacle pal\n"); | ||
335 | if2 = 33300 * 1000; | ||
336 | } | ||
337 | |||
338 | // per Manual for FM tuning: first if center freq. 1085 MHz | ||
339 | mt2032_set_if_freq(fe, params->frequency * 125 / 2, | ||
340 | 1085*1000*1000,if2,if2,if2); | ||
341 | |||
342 | return 0; | ||
343 | } | ||
344 | |||
345 | static int mt2032_set_params(struct dvb_frontend *fe, | ||
346 | struct analog_parameters *params) | ||
347 | { | ||
348 | struct microtune_priv *priv = fe->tuner_priv; | ||
349 | int ret = -EINVAL; | ||
350 | |||
351 | switch (params->mode) { | ||
352 | case V4L2_TUNER_RADIO: | ||
353 | ret = mt2032_set_radio_freq(fe, params); | ||
354 | priv->frequency = params->frequency * 125 / 2; | ||
355 | break; | ||
356 | case V4L2_TUNER_ANALOG_TV: | ||
357 | case V4L2_TUNER_DIGITAL_TV: | ||
358 | ret = mt2032_set_tv_freq(fe, params); | ||
359 | priv->frequency = params->frequency * 62500; | ||
360 | break; | ||
361 | } | ||
362 | |||
363 | return ret; | ||
364 | } | ||
365 | |||
366 | static struct dvb_tuner_ops mt2032_tuner_ops = { | ||
367 | .set_analog_params = mt2032_set_params, | ||
368 | .release = microtune_release, | ||
369 | .get_frequency = microtune_get_frequency, | ||
370 | }; | ||
371 | |||
372 | // Initialization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001 | ||
373 | static int mt2032_init(struct dvb_frontend *fe) | ||
374 | { | ||
375 | struct microtune_priv *priv = fe->tuner_priv; | ||
376 | unsigned char buf[21]; | ||
377 | int ret,xogc,xok=0; | ||
378 | |||
379 | // Initialize Registers per spec. | ||
380 | buf[1]=2; // Index to register 2 | ||
381 | buf[2]=0xff; | ||
382 | buf[3]=0x0f; | ||
383 | buf[4]=0x1f; | ||
384 | ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+1,4); | ||
385 | |||
386 | buf[5]=6; // Index register 6 | ||
387 | buf[6]=0xe4; | ||
388 | buf[7]=0x8f; | ||
389 | buf[8]=0xc3; | ||
390 | buf[9]=0x4e; | ||
391 | buf[10]=0xec; | ||
392 | ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+5,6); | ||
393 | |||
394 | buf[12]=13; // Index register 13 | ||
395 | buf[13]=0x32; | ||
396 | ret=tuner_i2c_xfer_send(&priv->i2c_props,buf+12,2); | ||
397 | |||
398 | // Adjust XOGC (register 7), wait for XOK | ||
399 | xogc=7; | ||
400 | do { | ||
401 | tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07); | ||
402 | mdelay(10); | ||
403 | buf[0]=0x0e; | ||
404 | tuner_i2c_xfer_send(&priv->i2c_props,buf,1); | ||
405 | tuner_i2c_xfer_recv(&priv->i2c_props,buf,1); | ||
406 | xok=buf[0]&0x01; | ||
407 | tuner_dbg("mt2032: xok = 0x%02x\n",xok); | ||
408 | if (xok == 1) break; | ||
409 | |||
410 | xogc--; | ||
411 | tuner_dbg("mt2032: xogc = 0x%02x\n",xogc&0x07); | ||
412 | if (xogc == 3) { | ||
413 | xogc=4; // min. 4 per spec | ||
414 | break; | ||
415 | } | ||
416 | buf[0]=0x07; | ||
417 | buf[1]=0x88 + xogc; | ||
418 | ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,2); | ||
419 | if (ret!=2) | ||
420 | tuner_warn("i2c i/o error: rc == %d (should be 2)\n",ret); | ||
421 | } while (xok != 1 ); | ||
422 | priv->xogc=xogc; | ||
423 | |||
424 | memcpy(&fe->ops.tuner_ops, &mt2032_tuner_ops, sizeof(struct dvb_tuner_ops)); | ||
425 | |||
426 | return(1); | ||
427 | } | ||
428 | |||
429 | static void mt2050_set_antenna(struct dvb_frontend *fe, unsigned char antenna) | ||
430 | { | ||
431 | struct microtune_priv *priv = fe->tuner_priv; | ||
432 | unsigned char buf[2]; | ||
433 | |||
434 | buf[0] = 6; | ||
435 | buf[1] = antenna ? 0x11 : 0x10; | ||
436 | tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); | ||
437 | tuner_dbg("mt2050: enabled antenna connector %d\n", antenna); | ||
438 | } | ||
439 | |||
440 | static void mt2050_set_if_freq(struct dvb_frontend *fe,unsigned int freq, unsigned int if2) | ||
441 | { | ||
442 | struct microtune_priv *priv = fe->tuner_priv; | ||
443 | unsigned int if1=1218*1000*1000; | ||
444 | unsigned int f_lo1,f_lo2,lo1,lo2,f_lo1_modulo,f_lo2_modulo,num1,num2,div1a,div1b,div2a,div2b; | ||
445 | int ret; | ||
446 | unsigned char buf[6]; | ||
447 | |||
448 | tuner_dbg("mt2050_set_if_freq freq=%d if1=%d if2=%d\n", | ||
449 | freq,if1,if2); | ||
450 | |||
451 | f_lo1=freq+if1; | ||
452 | f_lo1=(f_lo1/1000000)*1000000; | ||
453 | |||
454 | f_lo2=f_lo1-freq-if2; | ||
455 | f_lo2=(f_lo2/50000)*50000; | ||
456 | |||
457 | lo1=f_lo1/4000000; | ||
458 | lo2=f_lo2/4000000; | ||
459 | |||
460 | f_lo1_modulo= f_lo1-(lo1*4000000); | ||
461 | f_lo2_modulo= f_lo2-(lo2*4000000); | ||
462 | |||
463 | num1=4*f_lo1_modulo/4000000; | ||
464 | num2=4096*(f_lo2_modulo/1000)/4000; | ||
465 | |||
466 | // todo spurchecks | ||
467 | |||
468 | div1a=(lo1/12)-1; | ||
469 | div1b=lo1-(div1a+1)*12; | ||
470 | |||
471 | div2a=(lo2/8)-1; | ||
472 | div2b=lo2-(div2a+1)*8; | ||
473 | |||
474 | if (debug > 1) { | ||
475 | tuner_dbg("lo1 lo2 = %d %d\n", lo1, lo2); | ||
476 | tuner_dbg("num1 num2 div1a div1b div2a div2b= %x %x %x %x %x %x\n", | ||
477 | num1,num2,div1a,div1b,div2a,div2b); | ||
478 | } | ||
479 | |||
480 | buf[0]=1; | ||
481 | buf[1]= 4*div1b + num1; | ||
482 | if(freq<275*1000*1000) buf[1] = buf[1]|0x80; | ||
483 | |||
484 | buf[2]=div1a; | ||
485 | buf[3]=32*div2b + num2/256; | ||
486 | buf[4]=num2-(num2/256)*256; | ||
487 | buf[5]=div2a; | ||
488 | if(num2!=0) buf[5]=buf[5]|0x40; | ||
489 | |||
490 | if (debug > 1) { | ||
491 | int i; | ||
492 | tuner_dbg("bufs is: "); | ||
493 | for(i=0;i<6;i++) | ||
494 | printk("%x ",buf[i]); | ||
495 | printk("\n"); | ||
496 | } | ||
497 | |||
498 | ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,6); | ||
499 | if (ret!=6) | ||
500 | tuner_warn("i2c i/o error: rc == %d (should be 6)\n",ret); | ||
501 | } | ||
502 | |||
503 | static int mt2050_set_tv_freq(struct dvb_frontend *fe, | ||
504 | struct analog_parameters *params) | ||
505 | { | ||
506 | unsigned int if2; | ||
507 | |||
508 | if (params->std & V4L2_STD_525_60) { | ||
509 | // NTSC | ||
510 | if2 = 45750*1000; | ||
511 | } else { | ||
512 | // PAL | ||
513 | if2 = 38900*1000; | ||
514 | } | ||
515 | if (V4L2_TUNER_DIGITAL_TV == params->mode) { | ||
516 | // DVB (pinnacle 300i) | ||
517 | if2 = 36150*1000; | ||
518 | } | ||
519 | mt2050_set_if_freq(fe, params->frequency*62500, if2); | ||
520 | mt2050_set_antenna(fe, tv_antenna); | ||
521 | |||
522 | return 0; | ||
523 | } | ||
524 | |||
525 | static int mt2050_set_radio_freq(struct dvb_frontend *fe, | ||
526 | struct analog_parameters *params) | ||
527 | { | ||
528 | struct microtune_priv *priv = fe->tuner_priv; | ||
529 | int if2; | ||
530 | |||
531 | if (params->std & V4L2_STD_525_60) { | ||
532 | tuner_dbg("pinnacle ntsc\n"); | ||
533 | if2 = 41300 * 1000; | ||
534 | } else { | ||
535 | tuner_dbg("pinnacle pal\n"); | ||
536 | if2 = 33300 * 1000; | ||
537 | } | ||
538 | |||
539 | mt2050_set_if_freq(fe, params->frequency * 125 / 2, if2); | ||
540 | mt2050_set_antenna(fe, radio_antenna); | ||
541 | |||
542 | return 0; | ||
543 | } | ||
544 | |||
545 | static int mt2050_set_params(struct dvb_frontend *fe, | ||
546 | struct analog_parameters *params) | ||
547 | { | ||
548 | struct microtune_priv *priv = fe->tuner_priv; | ||
549 | int ret = -EINVAL; | ||
550 | |||
551 | switch (params->mode) { | ||
552 | case V4L2_TUNER_RADIO: | ||
553 | ret = mt2050_set_radio_freq(fe, params); | ||
554 | priv->frequency = params->frequency * 125 / 2; | ||
555 | break; | ||
556 | case V4L2_TUNER_ANALOG_TV: | ||
557 | case V4L2_TUNER_DIGITAL_TV: | ||
558 | ret = mt2050_set_tv_freq(fe, params); | ||
559 | priv->frequency = params->frequency * 62500; | ||
560 | break; | ||
561 | } | ||
562 | |||
563 | return ret; | ||
564 | } | ||
565 | |||
566 | static struct dvb_tuner_ops mt2050_tuner_ops = { | ||
567 | .set_analog_params = mt2050_set_params, | ||
568 | .release = microtune_release, | ||
569 | .get_frequency = microtune_get_frequency, | ||
570 | }; | ||
571 | |||
572 | static int mt2050_init(struct dvb_frontend *fe) | ||
573 | { | ||
574 | struct microtune_priv *priv = fe->tuner_priv; | ||
575 | unsigned char buf[2]; | ||
576 | |||
577 | buf[0] = 6; | ||
578 | buf[1] = 0x10; | ||
579 | tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); /* power */ | ||
580 | |||
581 | buf[0] = 0x0f; | ||
582 | buf[1] = 0x0f; | ||
583 | tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); /* m1lo */ | ||
584 | |||
585 | buf[0] = 0x0d; | ||
586 | tuner_i2c_xfer_send(&priv->i2c_props, buf, 1); | ||
587 | tuner_i2c_xfer_recv(&priv->i2c_props, buf, 1); | ||
588 | |||
589 | tuner_dbg("mt2050: sro is %x\n", buf[0]); | ||
590 | |||
591 | memcpy(&fe->ops.tuner_ops, &mt2050_tuner_ops, sizeof(struct dvb_tuner_ops)); | ||
592 | |||
593 | return 0; | ||
594 | } | ||
595 | |||
596 | struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, | ||
597 | struct i2c_adapter* i2c_adap, | ||
598 | u8 i2c_addr) | ||
599 | { | ||
600 | struct microtune_priv *priv = NULL; | ||
601 | char *name; | ||
602 | unsigned char buf[21]; | ||
603 | int company_code; | ||
604 | |||
605 | priv = kzalloc(sizeof(struct microtune_priv), GFP_KERNEL); | ||
606 | if (priv == NULL) | ||
607 | return NULL; | ||
608 | fe->tuner_priv = priv; | ||
609 | |||
610 | priv->i2c_props.addr = i2c_addr; | ||
611 | priv->i2c_props.adap = i2c_adap; | ||
612 | priv->i2c_props.name = "mt20xx"; | ||
613 | |||
614 | //priv->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */ | ||
615 | |||
616 | memset(buf,0,sizeof(buf)); | ||
617 | |||
618 | name = "unknown"; | ||
619 | |||
620 | tuner_i2c_xfer_send(&priv->i2c_props,buf,1); | ||
621 | tuner_i2c_xfer_recv(&priv->i2c_props,buf,21); | ||
622 | if (debug) { | ||
623 | int i; | ||
624 | tuner_dbg("MT20xx hexdump:"); | ||
625 | for(i=0;i<21;i++) { | ||
626 | printk(" %02x",buf[i]); | ||
627 | if(((i+1)%8)==0) printk(" "); | ||
628 | } | ||
629 | printk("\n"); | ||
630 | } | ||
631 | company_code = buf[0x11] << 8 | buf[0x12]; | ||
632 | tuner_info("microtune: companycode=%04x part=%02x rev=%02x\n", | ||
633 | company_code,buf[0x13],buf[0x14]); | ||
634 | |||
635 | |||
636 | if (buf[0x13] < ARRAY_SIZE(microtune_part) && | ||
637 | NULL != microtune_part[buf[0x13]]) | ||
638 | name = microtune_part[buf[0x13]]; | ||
639 | switch (buf[0x13]) { | ||
640 | case MT2032: | ||
641 | mt2032_init(fe); | ||
642 | break; | ||
643 | case MT2050: | ||
644 | mt2050_init(fe); | ||
645 | break; | ||
646 | default: | ||
647 | tuner_info("microtune %s found, not (yet?) supported, sorry :-/\n", | ||
648 | name); | ||
649 | return NULL; | ||
650 | } | ||
651 | |||
652 | strlcpy(fe->ops.tuner_ops.info.name, name, | ||
653 | sizeof(fe->ops.tuner_ops.info.name)); | ||
654 | tuner_info("microtune %s found, OK\n",name); | ||
655 | return fe; | ||
656 | } | ||
657 | |||
658 | EXPORT_SYMBOL_GPL(microtune_attach); | ||
659 | |||
660 | MODULE_DESCRIPTION("Microtune tuner driver"); | ||
661 | MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); | ||
662 | MODULE_LICENSE("GPL"); | ||
663 | |||
664 | /* | ||
665 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
666 | * --------------------------------------------------------------------------- | ||
667 | * Local variables: | ||
668 | * c-basic-offset: 8 | ||
669 | * End: | ||
670 | */ | ||
diff --git a/drivers/media/tuners/mt20xx.h b/drivers/media/tuners/mt20xx.h new file mode 100644 index 000000000000..259553a24903 --- /dev/null +++ b/drivers/media/tuners/mt20xx.h | |||
@@ -0,0 +1,37 @@ | |||
1 | /* | ||
2 | This program is free software; you can redistribute it and/or modify | ||
3 | it under the terms of the GNU General Public License as published by | ||
4 | the Free Software Foundation; either version 2 of the License, or | ||
5 | (at your option) any later version. | ||
6 | |||
7 | This program is distributed in the hope that it will be useful, | ||
8 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | GNU General Public License for more details. | ||
11 | |||
12 | You should have received a copy of the GNU General Public License | ||
13 | along with this program; if not, write to the Free Software | ||
14 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
15 | */ | ||
16 | |||
17 | #ifndef __MT20XX_H__ | ||
18 | #define __MT20XX_H__ | ||
19 | |||
20 | #include <linux/i2c.h> | ||
21 | #include "dvb_frontend.h" | ||
22 | |||
23 | #if defined(CONFIG_MEDIA_TUNER_MT20XX) || (defined(CONFIG_MEDIA_TUNER_MT20XX_MODULE) && defined(MODULE)) | ||
24 | extern struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, | ||
25 | struct i2c_adapter* i2c_adap, | ||
26 | u8 i2c_addr); | ||
27 | #else | ||
28 | static inline struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, | ||
29 | struct i2c_adapter* i2c_adap, | ||
30 | u8 i2c_addr) | ||
31 | { | ||
32 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
33 | return NULL; | ||
34 | } | ||
35 | #endif | ||
36 | |||
37 | #endif /* __MT20XX_H__ */ | ||
diff --git a/drivers/media/tuners/mt2131.c b/drivers/media/tuners/mt2131.c new file mode 100644 index 000000000000..f83b0c1ea6c8 --- /dev/null +++ b/drivers/media/tuners/mt2131.c | |||
@@ -0,0 +1,301 @@ | |||
1 | /* | ||
2 | * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" | ||
3 | * | ||
4 | * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org> | ||
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/delay.h> | ||
24 | #include <linux/dvb/frontend.h> | ||
25 | #include <linux/i2c.h> | ||
26 | #include <linux/slab.h> | ||
27 | |||
28 | #include "dvb_frontend.h" | ||
29 | |||
30 | #include "mt2131.h" | ||
31 | #include "mt2131_priv.h" | ||
32 | |||
33 | static int debug; | ||
34 | module_param(debug, int, 0644); | ||
35 | MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); | ||
36 | |||
37 | #define dprintk(level,fmt, arg...) if (debug >= level) \ | ||
38 | printk(KERN_INFO "%s: " fmt, "mt2131", ## arg) | ||
39 | |||
40 | static u8 mt2131_config1[] = { | ||
41 | 0x01, | ||
42 | 0x50, 0x00, 0x50, 0x80, 0x00, 0x49, 0xfa, 0x88, | ||
43 | 0x08, 0x77, 0x41, 0x04, 0x00, 0x00, 0x00, 0x32, | ||
44 | 0x7f, 0xda, 0x4c, 0x00, 0x10, 0xaa, 0x78, 0x80, | ||
45 | 0xff, 0x68, 0xa0, 0xff, 0xdd, 0x00, 0x00 | ||
46 | }; | ||
47 | |||
48 | static u8 mt2131_config2[] = { | ||
49 | 0x10, | ||
50 | 0x7f, 0xc8, 0x0a, 0x5f, 0x00, 0x04 | ||
51 | }; | ||
52 | |||
53 | static int mt2131_readreg(struct mt2131_priv *priv, u8 reg, u8 *val) | ||
54 | { | ||
55 | struct i2c_msg msg[2] = { | ||
56 | { .addr = priv->cfg->i2c_address, .flags = 0, | ||
57 | .buf = ®, .len = 1 }, | ||
58 | { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, | ||
59 | .buf = val, .len = 1 }, | ||
60 | }; | ||
61 | |||
62 | if (i2c_transfer(priv->i2c, msg, 2) != 2) { | ||
63 | printk(KERN_WARNING "mt2131 I2C read failed\n"); | ||
64 | return -EREMOTEIO; | ||
65 | } | ||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | static int mt2131_writereg(struct mt2131_priv *priv, u8 reg, u8 val) | ||
70 | { | ||
71 | u8 buf[2] = { reg, val }; | ||
72 | struct i2c_msg msg = { .addr = priv->cfg->i2c_address, .flags = 0, | ||
73 | .buf = buf, .len = 2 }; | ||
74 | |||
75 | if (i2c_transfer(priv->i2c, &msg, 1) != 1) { | ||
76 | printk(KERN_WARNING "mt2131 I2C write failed\n"); | ||
77 | return -EREMOTEIO; | ||
78 | } | ||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static int mt2131_writeregs(struct mt2131_priv *priv,u8 *buf, u8 len) | ||
83 | { | ||
84 | struct i2c_msg msg = { .addr = priv->cfg->i2c_address, | ||
85 | .flags = 0, .buf = buf, .len = len }; | ||
86 | |||
87 | if (i2c_transfer(priv->i2c, &msg, 1) != 1) { | ||
88 | printk(KERN_WARNING "mt2131 I2C write failed (len=%i)\n", | ||
89 | (int)len); | ||
90 | return -EREMOTEIO; | ||
91 | } | ||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | static int mt2131_set_params(struct dvb_frontend *fe) | ||
96 | { | ||
97 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
98 | struct mt2131_priv *priv; | ||
99 | int ret=0, i; | ||
100 | u32 freq; | ||
101 | u8 if_band_center; | ||
102 | u32 f_lo1, f_lo2; | ||
103 | u32 div1, num1, div2, num2; | ||
104 | u8 b[8]; | ||
105 | u8 lockval = 0; | ||
106 | |||
107 | priv = fe->tuner_priv; | ||
108 | |||
109 | freq = c->frequency / 1000; /* Hz -> kHz */ | ||
110 | dprintk(1, "%s() freq=%d\n", __func__, freq); | ||
111 | |||
112 | f_lo1 = freq + MT2131_IF1 * 1000; | ||
113 | f_lo1 = (f_lo1 / 250) * 250; | ||
114 | f_lo2 = f_lo1 - freq - MT2131_IF2; | ||
115 | |||
116 | priv->frequency = (f_lo1 - f_lo2 - MT2131_IF2) * 1000; | ||
117 | |||
118 | /* Frequency LO1 = 16MHz * (DIV1 + NUM1/8192 ) */ | ||
119 | num1 = f_lo1 * 64 / (MT2131_FREF / 128); | ||
120 | div1 = num1 / 8192; | ||
121 | num1 &= 0x1fff; | ||
122 | |||
123 | /* Frequency LO2 = 16MHz * (DIV2 + NUM2/8192 ) */ | ||
124 | num2 = f_lo2 * 64 / (MT2131_FREF / 128); | ||
125 | div2 = num2 / 8192; | ||
126 | num2 &= 0x1fff; | ||
127 | |||
128 | if (freq <= 82500) if_band_center = 0x00; else | ||
129 | if (freq <= 137500) if_band_center = 0x01; else | ||
130 | if (freq <= 192500) if_band_center = 0x02; else | ||
131 | if (freq <= 247500) if_band_center = 0x03; else | ||
132 | if (freq <= 302500) if_band_center = 0x04; else | ||
133 | if (freq <= 357500) if_band_center = 0x05; else | ||
134 | if (freq <= 412500) if_band_center = 0x06; else | ||
135 | if (freq <= 467500) if_band_center = 0x07; else | ||
136 | if (freq <= 522500) if_band_center = 0x08; else | ||
137 | if (freq <= 577500) if_band_center = 0x09; else | ||
138 | if (freq <= 632500) if_band_center = 0x0A; else | ||
139 | if (freq <= 687500) if_band_center = 0x0B; else | ||
140 | if (freq <= 742500) if_band_center = 0x0C; else | ||
141 | if (freq <= 797500) if_band_center = 0x0D; else | ||
142 | if (freq <= 852500) if_band_center = 0x0E; else | ||
143 | if (freq <= 907500) if_band_center = 0x0F; else | ||
144 | if (freq <= 962500) if_band_center = 0x10; else | ||
145 | if (freq <= 1017500) if_band_center = 0x11; else | ||
146 | if (freq <= 1072500) if_band_center = 0x12; else if_band_center = 0x13; | ||
147 | |||
148 | b[0] = 1; | ||
149 | b[1] = (num1 >> 5) & 0xFF; | ||
150 | b[2] = (num1 & 0x1F); | ||
151 | b[3] = div1; | ||
152 | b[4] = (num2 >> 5) & 0xFF; | ||
153 | b[5] = num2 & 0x1F; | ||
154 | b[6] = div2; | ||
155 | |||
156 | dprintk(1, "IF1: %dMHz IF2: %dMHz\n", MT2131_IF1, MT2131_IF2); | ||
157 | dprintk(1, "PLL freq=%dkHz band=%d\n", (int)freq, (int)if_band_center); | ||
158 | dprintk(1, "PLL f_lo1=%dkHz f_lo2=%dkHz\n", (int)f_lo1, (int)f_lo2); | ||
159 | dprintk(1, "PLL div1=%d num1=%d div2=%d num2=%d\n", | ||
160 | (int)div1, (int)num1, (int)div2, (int)num2); | ||
161 | dprintk(1, "PLL [1..6]: %2x %2x %2x %2x %2x %2x\n", | ||
162 | (int)b[1], (int)b[2], (int)b[3], (int)b[4], (int)b[5], | ||
163 | (int)b[6]); | ||
164 | |||
165 | ret = mt2131_writeregs(priv,b,7); | ||
166 | if (ret < 0) | ||
167 | return ret; | ||
168 | |||
169 | mt2131_writereg(priv, 0x0b, if_band_center); | ||
170 | |||
171 | /* Wait for lock */ | ||
172 | i = 0; | ||
173 | do { | ||
174 | mt2131_readreg(priv, 0x08, &lockval); | ||
175 | if ((lockval & 0x88) == 0x88) | ||
176 | break; | ||
177 | msleep(4); | ||
178 | i++; | ||
179 | } while (i < 10); | ||
180 | |||
181 | return ret; | ||
182 | } | ||
183 | |||
184 | static int mt2131_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
185 | { | ||
186 | struct mt2131_priv *priv = fe->tuner_priv; | ||
187 | dprintk(1, "%s()\n", __func__); | ||
188 | *frequency = priv->frequency; | ||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | static int mt2131_get_status(struct dvb_frontend *fe, u32 *status) | ||
193 | { | ||
194 | struct mt2131_priv *priv = fe->tuner_priv; | ||
195 | u8 lock_status = 0; | ||
196 | u8 afc_status = 0; | ||
197 | |||
198 | *status = 0; | ||
199 | |||
200 | mt2131_readreg(priv, 0x08, &lock_status); | ||
201 | if ((lock_status & 0x88) == 0x88) | ||
202 | *status = TUNER_STATUS_LOCKED; | ||
203 | |||
204 | mt2131_readreg(priv, 0x09, &afc_status); | ||
205 | dprintk(1, "%s() - LO Status = 0x%x, AFC Status = 0x%x\n", | ||
206 | __func__, lock_status, afc_status); | ||
207 | |||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | static int mt2131_init(struct dvb_frontend *fe) | ||
212 | { | ||
213 | struct mt2131_priv *priv = fe->tuner_priv; | ||
214 | int ret; | ||
215 | dprintk(1, "%s()\n", __func__); | ||
216 | |||
217 | if ((ret = mt2131_writeregs(priv, mt2131_config1, | ||
218 | sizeof(mt2131_config1))) < 0) | ||
219 | return ret; | ||
220 | |||
221 | mt2131_writereg(priv, 0x0b, 0x09); | ||
222 | mt2131_writereg(priv, 0x15, 0x47); | ||
223 | mt2131_writereg(priv, 0x07, 0xf2); | ||
224 | mt2131_writereg(priv, 0x0b, 0x01); | ||
225 | |||
226 | if ((ret = mt2131_writeregs(priv, mt2131_config2, | ||
227 | sizeof(mt2131_config2))) < 0) | ||
228 | return ret; | ||
229 | |||
230 | return ret; | ||
231 | } | ||
232 | |||
233 | static int mt2131_release(struct dvb_frontend *fe) | ||
234 | { | ||
235 | dprintk(1, "%s()\n", __func__); | ||
236 | kfree(fe->tuner_priv); | ||
237 | fe->tuner_priv = NULL; | ||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | static const struct dvb_tuner_ops mt2131_tuner_ops = { | ||
242 | .info = { | ||
243 | .name = "Microtune MT2131", | ||
244 | .frequency_min = 48000000, | ||
245 | .frequency_max = 860000000, | ||
246 | .frequency_step = 50000, | ||
247 | }, | ||
248 | |||
249 | .release = mt2131_release, | ||
250 | .init = mt2131_init, | ||
251 | |||
252 | .set_params = mt2131_set_params, | ||
253 | .get_frequency = mt2131_get_frequency, | ||
254 | .get_status = mt2131_get_status | ||
255 | }; | ||
256 | |||
257 | struct dvb_frontend * mt2131_attach(struct dvb_frontend *fe, | ||
258 | struct i2c_adapter *i2c, | ||
259 | struct mt2131_config *cfg, u16 if1) | ||
260 | { | ||
261 | struct mt2131_priv *priv = NULL; | ||
262 | u8 id = 0; | ||
263 | |||
264 | dprintk(1, "%s()\n", __func__); | ||
265 | |||
266 | priv = kzalloc(sizeof(struct mt2131_priv), GFP_KERNEL); | ||
267 | if (priv == NULL) | ||
268 | return NULL; | ||
269 | |||
270 | priv->cfg = cfg; | ||
271 | priv->i2c = i2c; | ||
272 | |||
273 | if (mt2131_readreg(priv, 0, &id) != 0) { | ||
274 | kfree(priv); | ||
275 | return NULL; | ||
276 | } | ||
277 | if ( (id != 0x3E) && (id != 0x3F) ) { | ||
278 | printk(KERN_ERR "MT2131: Device not found at addr 0x%02x\n", | ||
279 | cfg->i2c_address); | ||
280 | kfree(priv); | ||
281 | return NULL; | ||
282 | } | ||
283 | |||
284 | printk(KERN_INFO "MT2131: successfully identified at address 0x%02x\n", | ||
285 | cfg->i2c_address); | ||
286 | memcpy(&fe->ops.tuner_ops, &mt2131_tuner_ops, | ||
287 | sizeof(struct dvb_tuner_ops)); | ||
288 | |||
289 | fe->tuner_priv = priv; | ||
290 | return fe; | ||
291 | } | ||
292 | EXPORT_SYMBOL(mt2131_attach); | ||
293 | |||
294 | MODULE_AUTHOR("Steven Toth"); | ||
295 | MODULE_DESCRIPTION("Microtune MT2131 silicon tuner driver"); | ||
296 | MODULE_LICENSE("GPL"); | ||
297 | |||
298 | /* | ||
299 | * Local variables: | ||
300 | * c-basic-offset: 8 | ||
301 | */ | ||
diff --git a/drivers/media/tuners/mt2131.h b/drivers/media/tuners/mt2131.h new file mode 100644 index 000000000000..6632de640df0 --- /dev/null +++ b/drivers/media/tuners/mt2131.h | |||
@@ -0,0 +1,54 @@ | |||
1 | /* | ||
2 | * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" | ||
3 | * | ||
4 | * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org> | ||
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 __MT2131_H__ | ||
23 | #define __MT2131_H__ | ||
24 | |||
25 | struct dvb_frontend; | ||
26 | struct i2c_adapter; | ||
27 | |||
28 | struct mt2131_config { | ||
29 | u8 i2c_address; | ||
30 | u8 clock_out; /* 0 = off, 1 = CLK/4, 2 = CLK/2, 3 = CLK/1 */ | ||
31 | }; | ||
32 | |||
33 | #if defined(CONFIG_MEDIA_TUNER_MT2131) || (defined(CONFIG_MEDIA_TUNER_MT2131_MODULE) && defined(MODULE)) | ||
34 | extern struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, | ||
35 | struct i2c_adapter *i2c, | ||
36 | struct mt2131_config *cfg, | ||
37 | u16 if1); | ||
38 | #else | ||
39 | static inline struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe, | ||
40 | struct i2c_adapter *i2c, | ||
41 | struct mt2131_config *cfg, | ||
42 | u16 if1) | ||
43 | { | ||
44 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
45 | return NULL; | ||
46 | } | ||
47 | #endif /* CONFIG_MEDIA_TUNER_MT2131 */ | ||
48 | |||
49 | #endif /* __MT2131_H__ */ | ||
50 | |||
51 | /* | ||
52 | * Local variables: | ||
53 | * c-basic-offset: 8 | ||
54 | */ | ||
diff --git a/drivers/media/tuners/mt2131_priv.h b/drivers/media/tuners/mt2131_priv.h new file mode 100644 index 000000000000..62aeedf5c550 --- /dev/null +++ b/drivers/media/tuners/mt2131_priv.h | |||
@@ -0,0 +1,48 @@ | |||
1 | /* | ||
2 | * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" | ||
3 | * | ||
4 | * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org> | ||
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 __MT2131_PRIV_H__ | ||
23 | #define __MT2131_PRIV_H__ | ||
24 | |||
25 | /* Regs */ | ||
26 | #define MT2131_PWR 0x07 | ||
27 | #define MT2131_UPC_1 0x0b | ||
28 | #define MT2131_AGC_RL 0x10 | ||
29 | #define MT2131_MISC_2 0x15 | ||
30 | |||
31 | /* frequency values in KHz */ | ||
32 | #define MT2131_IF1 1220 | ||
33 | #define MT2131_IF2 44000 | ||
34 | #define MT2131_FREF 16000 | ||
35 | |||
36 | struct mt2131_priv { | ||
37 | struct mt2131_config *cfg; | ||
38 | struct i2c_adapter *i2c; | ||
39 | |||
40 | u32 frequency; | ||
41 | }; | ||
42 | |||
43 | #endif /* __MT2131_PRIV_H__ */ | ||
44 | |||
45 | /* | ||
46 | * Local variables: | ||
47 | * c-basic-offset: 8 | ||
48 | */ | ||
diff --git a/drivers/media/tuners/mt2266.c b/drivers/media/tuners/mt2266.c new file mode 100644 index 000000000000..bca4d75e42d4 --- /dev/null +++ b/drivers/media/tuners/mt2266.c | |||
@@ -0,0 +1,353 @@ | |||
1 | /* | ||
2 | * Driver for Microtune MT2266 "Direct conversion low power broadband tuner" | ||
3 | * | ||
4 | * Copyright (c) 2007 Olivier DANET <odanet@caramail.com> | ||
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 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/delay.h> | ||
19 | #include <linux/dvb/frontend.h> | ||
20 | #include <linux/i2c.h> | ||
21 | #include <linux/slab.h> | ||
22 | |||
23 | #include "dvb_frontend.h" | ||
24 | #include "mt2266.h" | ||
25 | |||
26 | #define I2C_ADDRESS 0x60 | ||
27 | |||
28 | #define REG_PART_REV 0 | ||
29 | #define REG_TUNE 1 | ||
30 | #define REG_BAND 6 | ||
31 | #define REG_BANDWIDTH 8 | ||
32 | #define REG_LOCK 0x12 | ||
33 | |||
34 | #define PART_REV 0x85 | ||
35 | |||
36 | struct mt2266_priv { | ||
37 | struct mt2266_config *cfg; | ||
38 | struct i2c_adapter *i2c; | ||
39 | |||
40 | u32 frequency; | ||
41 | u32 bandwidth; | ||
42 | u8 band; | ||
43 | }; | ||
44 | |||
45 | #define MT2266_VHF 1 | ||
46 | #define MT2266_UHF 0 | ||
47 | |||
48 | /* Here, frequencies are expressed in kiloHertz to avoid 32 bits overflows */ | ||
49 | |||
50 | static int debug; | ||
51 | module_param(debug, int, 0644); | ||
52 | MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); | ||
53 | |||
54 | #define dprintk(args...) do { if (debug) {printk(KERN_DEBUG "MT2266: " args); printk("\n"); }} while (0) | ||
55 | |||
56 | // Reads a single register | ||
57 | static int mt2266_readreg(struct mt2266_priv *priv, u8 reg, u8 *val) | ||
58 | { | ||
59 | struct i2c_msg msg[2] = { | ||
60 | { .addr = priv->cfg->i2c_address, .flags = 0, .buf = ®, .len = 1 }, | ||
61 | { .addr = priv->cfg->i2c_address, .flags = I2C_M_RD, .buf = val, .len = 1 }, | ||
62 | }; | ||
63 | if (i2c_transfer(priv->i2c, msg, 2) != 2) { | ||
64 | printk(KERN_WARNING "MT2266 I2C read failed\n"); | ||
65 | return -EREMOTEIO; | ||
66 | } | ||
67 | return 0; | ||
68 | } | ||
69 | |||
70 | // Writes a single register | ||
71 | static int mt2266_writereg(struct mt2266_priv *priv, u8 reg, u8 val) | ||
72 | { | ||
73 | u8 buf[2] = { reg, val }; | ||
74 | struct i2c_msg msg = { | ||
75 | .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = 2 | ||
76 | }; | ||
77 | if (i2c_transfer(priv->i2c, &msg, 1) != 1) { | ||
78 | printk(KERN_WARNING "MT2266 I2C write failed\n"); | ||
79 | return -EREMOTEIO; | ||
80 | } | ||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | // Writes a set of consecutive registers | ||
85 | static int mt2266_writeregs(struct mt2266_priv *priv,u8 *buf, u8 len) | ||
86 | { | ||
87 | struct i2c_msg msg = { | ||
88 | .addr = priv->cfg->i2c_address, .flags = 0, .buf = buf, .len = len | ||
89 | }; | ||
90 | if (i2c_transfer(priv->i2c, &msg, 1) != 1) { | ||
91 | printk(KERN_WARNING "MT2266 I2C write failed (len=%i)\n",(int)len); | ||
92 | return -EREMOTEIO; | ||
93 | } | ||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | // Initialisation sequences | ||
98 | static u8 mt2266_init1[] = { REG_TUNE, 0x00, 0x00, 0x28, | ||
99 | 0x00, 0x52, 0x99, 0x3f }; | ||
100 | |||
101 | static u8 mt2266_init2[] = { | ||
102 | 0x17, 0x6d, 0x71, 0x61, 0xc0, 0xbf, 0xff, 0xdc, 0x00, 0x0a, 0xd4, | ||
103 | 0x03, 0x64, 0x64, 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14, | ||
104 | 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x7f, 0x5e, 0x3f, 0xff, 0xff, | ||
105 | 0xff, 0x00, 0x77, 0x0f, 0x2d | ||
106 | }; | ||
107 | |||
108 | static u8 mt2266_init_8mhz[] = { REG_BANDWIDTH, 0x22, 0x22, 0x22, 0x22, | ||
109 | 0x22, 0x22, 0x22, 0x22 }; | ||
110 | |||
111 | static u8 mt2266_init_7mhz[] = { REG_BANDWIDTH, 0x32, 0x32, 0x32, 0x32, | ||
112 | 0x32, 0x32, 0x32, 0x32 }; | ||
113 | |||
114 | static u8 mt2266_init_6mhz[] = { REG_BANDWIDTH, 0xa7, 0xa7, 0xa7, 0xa7, | ||
115 | 0xa7, 0xa7, 0xa7, 0xa7 }; | ||
116 | |||
117 | static u8 mt2266_uhf[] = { 0x1d, 0xdc, 0x00, 0x0a, 0xd4, 0x03, 0x64, 0x64, | ||
118 | 0x64, 0x64, 0x22, 0xaa, 0xf2, 0x1e, 0x80, 0x14 }; | ||
119 | |||
120 | static u8 mt2266_vhf[] = { 0x1d, 0xfe, 0x00, 0x00, 0xb4, 0x03, 0xa5, 0xa5, | ||
121 | 0xa5, 0xa5, 0x82, 0xaa, 0xf1, 0x17, 0x80, 0x1f }; | ||
122 | |||
123 | #define FREF 30000 // Quartz oscillator 30 MHz | ||
124 | |||
125 | static int mt2266_set_params(struct dvb_frontend *fe) | ||
126 | { | ||
127 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
128 | struct mt2266_priv *priv; | ||
129 | int ret=0; | ||
130 | u32 freq; | ||
131 | u32 tune; | ||
132 | u8 lnaband; | ||
133 | u8 b[10]; | ||
134 | int i; | ||
135 | u8 band; | ||
136 | |||
137 | priv = fe->tuner_priv; | ||
138 | |||
139 | freq = priv->frequency / 1000; /* Hz -> kHz */ | ||
140 | if (freq < 470000 && freq > 230000) | ||
141 | return -EINVAL; /* Gap between VHF and UHF bands */ | ||
142 | |||
143 | priv->frequency = c->frequency; | ||
144 | tune = 2 * freq * (8192/16) / (FREF/16); | ||
145 | band = (freq < 300000) ? MT2266_VHF : MT2266_UHF; | ||
146 | if (band == MT2266_VHF) | ||
147 | tune *= 2; | ||
148 | |||
149 | switch (c->bandwidth_hz) { | ||
150 | case 6000000: | ||
151 | mt2266_writeregs(priv, mt2266_init_6mhz, | ||
152 | sizeof(mt2266_init_6mhz)); | ||
153 | break; | ||
154 | case 8000000: | ||
155 | mt2266_writeregs(priv, mt2266_init_8mhz, | ||
156 | sizeof(mt2266_init_8mhz)); | ||
157 | break; | ||
158 | case 7000000: | ||
159 | default: | ||
160 | mt2266_writeregs(priv, mt2266_init_7mhz, | ||
161 | sizeof(mt2266_init_7mhz)); | ||
162 | break; | ||
163 | } | ||
164 | priv->bandwidth = c->bandwidth_hz; | ||
165 | |||
166 | if (band == MT2266_VHF && priv->band == MT2266_UHF) { | ||
167 | dprintk("Switch from UHF to VHF"); | ||
168 | mt2266_writereg(priv, 0x05, 0x04); | ||
169 | mt2266_writereg(priv, 0x19, 0x61); | ||
170 | mt2266_writeregs(priv, mt2266_vhf, sizeof(mt2266_vhf)); | ||
171 | } else if (band == MT2266_UHF && priv->band == MT2266_VHF) { | ||
172 | dprintk("Switch from VHF to UHF"); | ||
173 | mt2266_writereg(priv, 0x05, 0x52); | ||
174 | mt2266_writereg(priv, 0x19, 0x61); | ||
175 | mt2266_writeregs(priv, mt2266_uhf, sizeof(mt2266_uhf)); | ||
176 | } | ||
177 | msleep(10); | ||
178 | |||
179 | if (freq <= 495000) | ||
180 | lnaband = 0xEE; | ||
181 | else if (freq <= 525000) | ||
182 | lnaband = 0xDD; | ||
183 | else if (freq <= 550000) | ||
184 | lnaband = 0xCC; | ||
185 | else if (freq <= 580000) | ||
186 | lnaband = 0xBB; | ||
187 | else if (freq <= 605000) | ||
188 | lnaband = 0xAA; | ||
189 | else if (freq <= 630000) | ||
190 | lnaband = 0x99; | ||
191 | else if (freq <= 655000) | ||
192 | lnaband = 0x88; | ||
193 | else if (freq <= 685000) | ||
194 | lnaband = 0x77; | ||
195 | else if (freq <= 710000) | ||
196 | lnaband = 0x66; | ||
197 | else if (freq <= 735000) | ||
198 | lnaband = 0x55; | ||
199 | else if (freq <= 765000) | ||
200 | lnaband = 0x44; | ||
201 | else if (freq <= 802000) | ||
202 | lnaband = 0x33; | ||
203 | else if (freq <= 840000) | ||
204 | lnaband = 0x22; | ||
205 | else | ||
206 | lnaband = 0x11; | ||
207 | |||
208 | b[0] = REG_TUNE; | ||
209 | b[1] = (tune >> 8) & 0x1F; | ||
210 | b[2] = tune & 0xFF; | ||
211 | b[3] = tune >> 13; | ||
212 | mt2266_writeregs(priv,b,4); | ||
213 | |||
214 | dprintk("set_parms: tune=%d band=%d %s", | ||
215 | (int) tune, (int) lnaband, | ||
216 | (band == MT2266_UHF) ? "UHF" : "VHF"); | ||
217 | dprintk("set_parms: [1..3]: %2x %2x %2x", | ||
218 | (int) b[1], (int) b[2], (int)b[3]); | ||
219 | |||
220 | if (band == MT2266_UHF) { | ||
221 | b[0] = 0x05; | ||
222 | b[1] = (priv->band == MT2266_VHF) ? 0x52 : 0x62; | ||
223 | b[2] = lnaband; | ||
224 | mt2266_writeregs(priv, b, 3); | ||
225 | } | ||
226 | |||
227 | /* Wait for pll lock or timeout */ | ||
228 | i = 0; | ||
229 | do { | ||
230 | mt2266_readreg(priv,REG_LOCK,b); | ||
231 | if (b[0] & 0x40) | ||
232 | break; | ||
233 | msleep(10); | ||
234 | i++; | ||
235 | } while (i<10); | ||
236 | dprintk("Lock when i=%i",(int)i); | ||
237 | |||
238 | if (band == MT2266_UHF && priv->band == MT2266_VHF) | ||
239 | mt2266_writereg(priv, 0x05, 0x62); | ||
240 | |||
241 | priv->band = band; | ||
242 | |||
243 | return ret; | ||
244 | } | ||
245 | |||
246 | static void mt2266_calibrate(struct mt2266_priv *priv) | ||
247 | { | ||
248 | mt2266_writereg(priv, 0x11, 0x03); | ||
249 | mt2266_writereg(priv, 0x11, 0x01); | ||
250 | mt2266_writeregs(priv, mt2266_init1, sizeof(mt2266_init1)); | ||
251 | mt2266_writeregs(priv, mt2266_init2, sizeof(mt2266_init2)); | ||
252 | mt2266_writereg(priv, 0x33, 0x5e); | ||
253 | mt2266_writereg(priv, 0x10, 0x10); | ||
254 | mt2266_writereg(priv, 0x10, 0x00); | ||
255 | mt2266_writeregs(priv, mt2266_init_8mhz, sizeof(mt2266_init_8mhz)); | ||
256 | msleep(25); | ||
257 | mt2266_writereg(priv, 0x17, 0x6d); | ||
258 | mt2266_writereg(priv, 0x1c, 0x00); | ||
259 | msleep(75); | ||
260 | mt2266_writereg(priv, 0x17, 0x6d); | ||
261 | mt2266_writereg(priv, 0x1c, 0xff); | ||
262 | } | ||
263 | |||
264 | static int mt2266_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
265 | { | ||
266 | struct mt2266_priv *priv = fe->tuner_priv; | ||
267 | *frequency = priv->frequency; | ||
268 | return 0; | ||
269 | } | ||
270 | |||
271 | static int mt2266_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) | ||
272 | { | ||
273 | struct mt2266_priv *priv = fe->tuner_priv; | ||
274 | *bandwidth = priv->bandwidth; | ||
275 | return 0; | ||
276 | } | ||
277 | |||
278 | static int mt2266_init(struct dvb_frontend *fe) | ||
279 | { | ||
280 | int ret; | ||
281 | struct mt2266_priv *priv = fe->tuner_priv; | ||
282 | ret = mt2266_writereg(priv, 0x17, 0x6d); | ||
283 | if (ret < 0) | ||
284 | return ret; | ||
285 | ret = mt2266_writereg(priv, 0x1c, 0xff); | ||
286 | if (ret < 0) | ||
287 | return ret; | ||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | static int mt2266_sleep(struct dvb_frontend *fe) | ||
292 | { | ||
293 | struct mt2266_priv *priv = fe->tuner_priv; | ||
294 | mt2266_writereg(priv, 0x17, 0x6d); | ||
295 | mt2266_writereg(priv, 0x1c, 0x00); | ||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | static int mt2266_release(struct dvb_frontend *fe) | ||
300 | { | ||
301 | kfree(fe->tuner_priv); | ||
302 | fe->tuner_priv = NULL; | ||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | static const struct dvb_tuner_ops mt2266_tuner_ops = { | ||
307 | .info = { | ||
308 | .name = "Microtune MT2266", | ||
309 | .frequency_min = 174000000, | ||
310 | .frequency_max = 862000000, | ||
311 | .frequency_step = 50000, | ||
312 | }, | ||
313 | .release = mt2266_release, | ||
314 | .init = mt2266_init, | ||
315 | .sleep = mt2266_sleep, | ||
316 | .set_params = mt2266_set_params, | ||
317 | .get_frequency = mt2266_get_frequency, | ||
318 | .get_bandwidth = mt2266_get_bandwidth | ||
319 | }; | ||
320 | |||
321 | struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg) | ||
322 | { | ||
323 | struct mt2266_priv *priv = NULL; | ||
324 | u8 id = 0; | ||
325 | |||
326 | priv = kzalloc(sizeof(struct mt2266_priv), GFP_KERNEL); | ||
327 | if (priv == NULL) | ||
328 | return NULL; | ||
329 | |||
330 | priv->cfg = cfg; | ||
331 | priv->i2c = i2c; | ||
332 | priv->band = MT2266_UHF; | ||
333 | |||
334 | if (mt2266_readreg(priv, 0, &id)) { | ||
335 | kfree(priv); | ||
336 | return NULL; | ||
337 | } | ||
338 | if (id != PART_REV) { | ||
339 | kfree(priv); | ||
340 | return NULL; | ||
341 | } | ||
342 | printk(KERN_INFO "MT2266: successfully identified\n"); | ||
343 | memcpy(&fe->ops.tuner_ops, &mt2266_tuner_ops, sizeof(struct dvb_tuner_ops)); | ||
344 | |||
345 | fe->tuner_priv = priv; | ||
346 | mt2266_calibrate(priv); | ||
347 | return fe; | ||
348 | } | ||
349 | EXPORT_SYMBOL(mt2266_attach); | ||
350 | |||
351 | MODULE_AUTHOR("Olivier DANET"); | ||
352 | MODULE_DESCRIPTION("Microtune MT2266 silicon tuner driver"); | ||
353 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/tuners/mt2266.h b/drivers/media/tuners/mt2266.h new file mode 100644 index 000000000000..4d083882d044 --- /dev/null +++ b/drivers/media/tuners/mt2266.h | |||
@@ -0,0 +1,37 @@ | |||
1 | /* | ||
2 | * Driver for Microtune MT2266 "Direct conversion low power broadband tuner" | ||
3 | * | ||
4 | * Copyright (c) 2007 Olivier DANET <odanet@caramail.com> | ||
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 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #ifndef MT2266_H | ||
18 | #define MT2266_H | ||
19 | |||
20 | struct dvb_frontend; | ||
21 | struct i2c_adapter; | ||
22 | |||
23 | struct mt2266_config { | ||
24 | u8 i2c_address; | ||
25 | }; | ||
26 | |||
27 | #if defined(CONFIG_MEDIA_TUNER_MT2266) || (defined(CONFIG_MEDIA_TUNER_MT2266_MODULE) && defined(MODULE)) | ||
28 | extern struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg); | ||
29 | #else | ||
30 | static inline struct dvb_frontend * mt2266_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct mt2266_config *cfg) | ||
31 | { | ||
32 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
33 | return NULL; | ||
34 | } | ||
35 | #endif // CONFIG_MEDIA_TUNER_MT2266 | ||
36 | |||
37 | #endif | ||
diff --git a/drivers/media/tuners/mxl5005s.c b/drivers/media/tuners/mxl5005s.c new file mode 100644 index 000000000000..6133315fb0e3 --- /dev/null +++ b/drivers/media/tuners/mxl5005s.c | |||
@@ -0,0 +1,4109 @@ | |||
1 | /* | ||
2 | MaxLinear MXL5005S VSB/QAM/DVBT tuner driver | ||
3 | |||
4 | Copyright (C) 2008 MaxLinear | ||
5 | Copyright (C) 2006 Steven Toth <stoth@linuxtv.org> | ||
6 | Functions: | ||
7 | mxl5005s_reset() | ||
8 | mxl5005s_writereg() | ||
9 | mxl5005s_writeregs() | ||
10 | mxl5005s_init() | ||
11 | mxl5005s_reconfigure() | ||
12 | mxl5005s_AssignTunerMode() | ||
13 | mxl5005s_set_params() | ||
14 | mxl5005s_get_frequency() | ||
15 | mxl5005s_get_bandwidth() | ||
16 | mxl5005s_release() | ||
17 | mxl5005s_attach() | ||
18 | |||
19 | Copyright (C) 2008 Realtek | ||
20 | Copyright (C) 2008 Jan Hoogenraad | ||
21 | Functions: | ||
22 | mxl5005s_SetRfFreqHz() | ||
23 | |||
24 | This program is free software; you can redistribute it and/or modify | ||
25 | it under the terms of the GNU General Public License as published by | ||
26 | the Free Software Foundation; either version 2 of the License, or | ||
27 | (at your option) any later version. | ||
28 | |||
29 | This program is distributed in the hope that it will be useful, | ||
30 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
31 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
32 | GNU General Public License for more details. | ||
33 | |||
34 | You should have received a copy of the GNU General Public License | ||
35 | along with this program; if not, write to the Free Software | ||
36 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
37 | |||
38 | */ | ||
39 | |||
40 | /* | ||
41 | History of this driver (Steven Toth): | ||
42 | I was given a public release of a linux driver that included | ||
43 | support for the MaxLinear MXL5005S silicon tuner. Analysis of | ||
44 | the tuner driver showed clearly three things. | ||
45 | |||
46 | 1. The tuner driver didn't support the LinuxTV tuner API | ||
47 | so the code Realtek added had to be removed. | ||
48 | |||
49 | 2. A significant amount of the driver is reference driver code | ||
50 | from MaxLinear, I felt it was important to identify and | ||
51 | preserve this. | ||
52 | |||
53 | 3. New code has to be added to interface correctly with the | ||
54 | LinuxTV API, as a regular kernel module. | ||
55 | |||
56 | Other than the reference driver enum's, I've clearly marked | ||
57 | sections of the code and retained the copyright of the | ||
58 | respective owners. | ||
59 | */ | ||
60 | #include <linux/kernel.h> | ||
61 | #include <linux/init.h> | ||
62 | #include <linux/module.h> | ||
63 | #include <linux/string.h> | ||
64 | #include <linux/slab.h> | ||
65 | #include <linux/delay.h> | ||
66 | #include "dvb_frontend.h" | ||
67 | #include "mxl5005s.h" | ||
68 | |||
69 | static int debug; | ||
70 | |||
71 | #define dprintk(level, arg...) do { \ | ||
72 | if (level <= debug) \ | ||
73 | printk(arg); \ | ||
74 | } while (0) | ||
75 | |||
76 | #define TUNER_REGS_NUM 104 | ||
77 | #define INITCTRL_NUM 40 | ||
78 | |||
79 | #ifdef _MXL_PRODUCTION | ||
80 | #define CHCTRL_NUM 39 | ||
81 | #else | ||
82 | #define CHCTRL_NUM 36 | ||
83 | #endif | ||
84 | |||
85 | #define MXLCTRL_NUM 189 | ||
86 | #define MASTER_CONTROL_ADDR 9 | ||
87 | |||
88 | /* Enumeration of Master Control Register State */ | ||
89 | enum master_control_state { | ||
90 | MC_LOAD_START = 1, | ||
91 | MC_POWER_DOWN, | ||
92 | MC_SYNTH_RESET, | ||
93 | MC_SEQ_OFF | ||
94 | }; | ||
95 | |||
96 | /* Enumeration of MXL5005 Tuner Modulation Type */ | ||
97 | enum { | ||
98 | MXL_DEFAULT_MODULATION = 0, | ||
99 | MXL_DVBT, | ||
100 | MXL_ATSC, | ||
101 | MXL_QAM, | ||
102 | MXL_ANALOG_CABLE, | ||
103 | MXL_ANALOG_OTA | ||
104 | }; | ||
105 | |||
106 | /* MXL5005 Tuner Register Struct */ | ||
107 | struct TunerReg { | ||
108 | u16 Reg_Num; /* Tuner Register Address */ | ||
109 | u16 Reg_Val; /* Current sw programmed value waiting to be written */ | ||
110 | }; | ||
111 | |||
112 | enum { | ||
113 | /* Initialization Control Names */ | ||
114 | DN_IQTN_AMP_CUT = 1, /* 1 */ | ||
115 | BB_MODE, /* 2 */ | ||
116 | BB_BUF, /* 3 */ | ||
117 | BB_BUF_OA, /* 4 */ | ||
118 | BB_ALPF_BANDSELECT, /* 5 */ | ||
119 | BB_IQSWAP, /* 6 */ | ||
120 | BB_DLPF_BANDSEL, /* 7 */ | ||
121 | RFSYN_CHP_GAIN, /* 8 */ | ||
122 | RFSYN_EN_CHP_HIGAIN, /* 9 */ | ||
123 | AGC_IF, /* 10 */ | ||
124 | AGC_RF, /* 11 */ | ||
125 | IF_DIVVAL, /* 12 */ | ||
126 | IF_VCO_BIAS, /* 13 */ | ||
127 | CHCAL_INT_MOD_IF, /* 14 */ | ||
128 | CHCAL_FRAC_MOD_IF, /* 15 */ | ||
129 | DRV_RES_SEL, /* 16 */ | ||
130 | I_DRIVER, /* 17 */ | ||
131 | EN_AAF, /* 18 */ | ||
132 | EN_3P, /* 19 */ | ||
133 | EN_AUX_3P, /* 20 */ | ||
134 | SEL_AAF_BAND, /* 21 */ | ||
135 | SEQ_ENCLK16_CLK_OUT, /* 22 */ | ||
136 | SEQ_SEL4_16B, /* 23 */ | ||
137 | XTAL_CAPSELECT, /* 24 */ | ||
138 | IF_SEL_DBL, /* 25 */ | ||
139 | RFSYN_R_DIV, /* 26 */ | ||
140 | SEQ_EXTSYNTHCALIF, /* 27 */ | ||
141 | SEQ_EXTDCCAL, /* 28 */ | ||
142 | AGC_EN_RSSI, /* 29 */ | ||
143 | RFA_ENCLKRFAGC, /* 30 */ | ||
144 | RFA_RSSI_REFH, /* 31 */ | ||
145 | RFA_RSSI_REF, /* 32 */ | ||
146 | RFA_RSSI_REFL, /* 33 */ | ||
147 | RFA_FLR, /* 34 */ | ||
148 | RFA_CEIL, /* 35 */ | ||
149 | SEQ_EXTIQFSMPULSE, /* 36 */ | ||
150 | OVERRIDE_1, /* 37 */ | ||
151 | BB_INITSTATE_DLPF_TUNE, /* 38 */ | ||
152 | TG_R_DIV, /* 39 */ | ||
153 | EN_CHP_LIN_B, /* 40 */ | ||
154 | |||
155 | /* Channel Change Control Names */ | ||
156 | DN_POLY = 51, /* 51 */ | ||
157 | DN_RFGAIN, /* 52 */ | ||
158 | DN_CAP_RFLPF, /* 53 */ | ||
159 | DN_EN_VHFUHFBAR, /* 54 */ | ||
160 | DN_GAIN_ADJUST, /* 55 */ | ||
161 | DN_IQTNBUF_AMP, /* 56 */ | ||
162 | DN_IQTNGNBFBIAS_BST, /* 57 */ | ||
163 | RFSYN_EN_OUTMUX, /* 58 */ | ||
164 | RFSYN_SEL_VCO_OUT, /* 59 */ | ||
165 | RFSYN_SEL_VCO_HI, /* 60 */ | ||
166 | RFSYN_SEL_DIVM, /* 61 */ | ||
167 | RFSYN_RF_DIV_BIAS, /* 62 */ | ||
168 | DN_SEL_FREQ, /* 63 */ | ||
169 | RFSYN_VCO_BIAS, /* 64 */ | ||
170 | CHCAL_INT_MOD_RF, /* 65 */ | ||
171 | CHCAL_FRAC_MOD_RF, /* 66 */ | ||
172 | RFSYN_LPF_R, /* 67 */ | ||
173 | CHCAL_EN_INT_RF, /* 68 */ | ||
174 | TG_LO_DIVVAL, /* 69 */ | ||
175 | TG_LO_SELVAL, /* 70 */ | ||
176 | TG_DIV_VAL, /* 71 */ | ||
177 | TG_VCO_BIAS, /* 72 */ | ||
178 | SEQ_EXTPOWERUP, /* 73 */ | ||
179 | OVERRIDE_2, /* 74 */ | ||
180 | OVERRIDE_3, /* 75 */ | ||
181 | OVERRIDE_4, /* 76 */ | ||
182 | SEQ_FSM_PULSE, /* 77 */ | ||
183 | GPIO_4B, /* 78 */ | ||
184 | GPIO_3B, /* 79 */ | ||
185 | GPIO_4, /* 80 */ | ||
186 | GPIO_3, /* 81 */ | ||
187 | GPIO_1B, /* 82 */ | ||
188 | DAC_A_ENABLE, /* 83 */ | ||
189 | DAC_B_ENABLE, /* 84 */ | ||
190 | DAC_DIN_A, /* 85 */ | ||
191 | DAC_DIN_B, /* 86 */ | ||
192 | #ifdef _MXL_PRODUCTION | ||
193 | RFSYN_EN_DIV, /* 87 */ | ||
194 | RFSYN_DIVM, /* 88 */ | ||
195 | DN_BYPASS_AGC_I2C /* 89 */ | ||
196 | #endif | ||
197 | }; | ||
198 | |||
199 | /* | ||
200 | * The following context is source code provided by MaxLinear. | ||
201 | * MaxLinear source code - Common_MXL.h (?) | ||
202 | */ | ||
203 | |||
204 | /* Constants */ | ||
205 | #define MXL5005S_REG_WRITING_TABLE_LEN_MAX 104 | ||
206 | #define MXL5005S_LATCH_BYTE 0xfe | ||
207 | |||
208 | /* Register address, MSB, and LSB */ | ||
209 | #define MXL5005S_BB_IQSWAP_ADDR 59 | ||
210 | #define MXL5005S_BB_IQSWAP_MSB 0 | ||
211 | #define MXL5005S_BB_IQSWAP_LSB 0 | ||
212 | |||
213 | #define MXL5005S_BB_DLPF_BANDSEL_ADDR 53 | ||
214 | #define MXL5005S_BB_DLPF_BANDSEL_MSB 4 | ||
215 | #define MXL5005S_BB_DLPF_BANDSEL_LSB 3 | ||
216 | |||
217 | /* Standard modes */ | ||
218 | enum { | ||
219 | MXL5005S_STANDARD_DVBT, | ||
220 | MXL5005S_STANDARD_ATSC, | ||
221 | }; | ||
222 | #define MXL5005S_STANDARD_MODE_NUM 2 | ||
223 | |||
224 | /* Bandwidth modes */ | ||
225 | enum { | ||
226 | MXL5005S_BANDWIDTH_6MHZ = 6000000, | ||
227 | MXL5005S_BANDWIDTH_7MHZ = 7000000, | ||
228 | MXL5005S_BANDWIDTH_8MHZ = 8000000, | ||
229 | }; | ||
230 | #define MXL5005S_BANDWIDTH_MODE_NUM 3 | ||
231 | |||
232 | /* MXL5005 Tuner Control Struct */ | ||
233 | struct TunerControl { | ||
234 | u16 Ctrl_Num; /* Control Number */ | ||
235 | u16 size; /* Number of bits to represent Value */ | ||
236 | u16 addr[25]; /* Array of Tuner Register Address for each bit pos */ | ||
237 | u16 bit[25]; /* Array of bit pos in Reg Addr for each bit pos */ | ||
238 | u16 val[25]; /* Binary representation of Value */ | ||
239 | }; | ||
240 | |||
241 | /* MXL5005 Tuner Struct */ | ||
242 | struct mxl5005s_state { | ||
243 | u8 Mode; /* 0: Analog Mode ; 1: Digital Mode */ | ||
244 | u8 IF_Mode; /* for Analog Mode, 0: zero IF; 1: low IF */ | ||
245 | u32 Chan_Bandwidth; /* filter channel bandwidth (6, 7, 8) */ | ||
246 | u32 IF_OUT; /* Desired IF Out Frequency */ | ||
247 | u16 IF_OUT_LOAD; /* IF Out Load Resistor (200/300 Ohms) */ | ||
248 | u32 RF_IN; /* RF Input Frequency */ | ||
249 | u32 Fxtal; /* XTAL Frequency */ | ||
250 | u8 AGC_Mode; /* AGC Mode 0: Dual AGC; 1: Single AGC */ | ||
251 | u16 TOP; /* Value: take over point */ | ||
252 | u8 CLOCK_OUT; /* 0: turn off clk out; 1: turn on clock out */ | ||
253 | u8 DIV_OUT; /* 4MHz or 16MHz */ | ||
254 | u8 CAPSELECT; /* 0: disable On-Chip pulling cap; 1: enable */ | ||
255 | u8 EN_RSSI; /* 0: disable RSSI; 1: enable RSSI */ | ||
256 | |||
257 | /* Modulation Type; */ | ||
258 | /* 0 - Default; 1 - DVB-T; 2 - ATSC; 3 - QAM; 4 - Analog Cable */ | ||
259 | u8 Mod_Type; | ||
260 | |||
261 | /* Tracking Filter Type */ | ||
262 | /* 0 - Default; 1 - Off; 2 - Type C; 3 - Type C-H */ | ||
263 | u8 TF_Type; | ||
264 | |||
265 | /* Calculated Settings */ | ||
266 | u32 RF_LO; /* Synth RF LO Frequency */ | ||
267 | u32 IF_LO; /* Synth IF LO Frequency */ | ||
268 | u32 TG_LO; /* Synth TG_LO Frequency */ | ||
269 | |||
270 | /* Pointers to ControlName Arrays */ | ||
271 | u16 Init_Ctrl_Num; /* Number of INIT Control Names */ | ||
272 | struct TunerControl | ||
273 | Init_Ctrl[INITCTRL_NUM]; /* INIT Control Names Array Pointer */ | ||
274 | |||
275 | u16 CH_Ctrl_Num; /* Number of CH Control Names */ | ||
276 | struct TunerControl | ||
277 | CH_Ctrl[CHCTRL_NUM]; /* CH Control Name Array Pointer */ | ||
278 | |||
279 | u16 MXL_Ctrl_Num; /* Number of MXL Control Names */ | ||
280 | struct TunerControl | ||
281 | MXL_Ctrl[MXLCTRL_NUM]; /* MXL Control Name Array Pointer */ | ||
282 | |||
283 | /* Pointer to Tuner Register Array */ | ||
284 | u16 TunerRegs_Num; /* Number of Tuner Registers */ | ||
285 | struct TunerReg | ||
286 | TunerRegs[TUNER_REGS_NUM]; /* Tuner Register Array Pointer */ | ||
287 | |||
288 | /* Linux driver framework specific */ | ||
289 | struct mxl5005s_config *config; | ||
290 | struct dvb_frontend *frontend; | ||
291 | struct i2c_adapter *i2c; | ||
292 | |||
293 | /* Cache values */ | ||
294 | u32 current_mode; | ||
295 | |||
296 | }; | ||
297 | |||
298 | static u16 MXL_GetMasterControl(u8 *MasterReg, int state); | ||
299 | static u16 MXL_ControlWrite(struct dvb_frontend *fe, u16 ControlNum, u32 value); | ||
300 | static u16 MXL_ControlRead(struct dvb_frontend *fe, u16 controlNum, u32 *value); | ||
301 | static void MXL_RegWriteBit(struct dvb_frontend *fe, u8 address, u8 bit, | ||
302 | u8 bitVal); | ||
303 | static u16 MXL_GetCHRegister(struct dvb_frontend *fe, u8 *RegNum, | ||
304 | u8 *RegVal, int *count); | ||
305 | static u32 MXL_Ceiling(u32 value, u32 resolution); | ||
306 | static u16 MXL_RegRead(struct dvb_frontend *fe, u8 RegNum, u8 *RegVal); | ||
307 | static u16 MXL_ControlWrite_Group(struct dvb_frontend *fe, u16 controlNum, | ||
308 | u32 value, u16 controlGroup); | ||
309 | static u16 MXL_SetGPIO(struct dvb_frontend *fe, u8 GPIO_Num, u8 GPIO_Val); | ||
310 | static u16 MXL_GetInitRegister(struct dvb_frontend *fe, u8 *RegNum, | ||
311 | u8 *RegVal, int *count); | ||
312 | static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq); | ||
313 | static void MXL_SynthIFLO_Calc(struct dvb_frontend *fe); | ||
314 | static void MXL_SynthRFTGLO_Calc(struct dvb_frontend *fe); | ||
315 | static u16 MXL_GetCHRegister_ZeroIF(struct dvb_frontend *fe, u8 *RegNum, | ||
316 | u8 *RegVal, int *count); | ||
317 | static int mxl5005s_writeregs(struct dvb_frontend *fe, u8 *addrtable, | ||
318 | u8 *datatable, u8 len); | ||
319 | static u16 MXL_IFSynthInit(struct dvb_frontend *fe); | ||
320 | static int mxl5005s_AssignTunerMode(struct dvb_frontend *fe, u32 mod_type, | ||
321 | u32 bandwidth); | ||
322 | static int mxl5005s_reconfigure(struct dvb_frontend *fe, u32 mod_type, | ||
323 | u32 bandwidth); | ||
324 | |||
325 | /* ---------------------------------------------------------------- | ||
326 | * Begin: Custom code salvaged from the Realtek driver. | ||
327 | * Copyright (C) 2008 Realtek | ||
328 | * Copyright (C) 2008 Jan Hoogenraad | ||
329 | * This code is placed under the terms of the GNU General Public License | ||
330 | * | ||
331 | * Released by Realtek under GPLv2. | ||
332 | * Thanks to Realtek for a lot of support we received ! | ||
333 | * | ||
334 | * Revision: 080314 - original version | ||
335 | */ | ||
336 | |||
337 | static int mxl5005s_SetRfFreqHz(struct dvb_frontend *fe, unsigned long RfFreqHz) | ||
338 | { | ||
339 | struct mxl5005s_state *state = fe->tuner_priv; | ||
340 | unsigned char AddrTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX]; | ||
341 | unsigned char ByteTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX]; | ||
342 | int TableLen; | ||
343 | |||
344 | u32 IfDivval = 0; | ||
345 | unsigned char MasterControlByte; | ||
346 | |||
347 | dprintk(1, "%s() freq=%ld\n", __func__, RfFreqHz); | ||
348 | |||
349 | /* Set MxL5005S tuner RF frequency according to example code. */ | ||
350 | |||
351 | /* Tuner RF frequency setting stage 0 */ | ||
352 | MXL_GetMasterControl(ByteTable, MC_SYNTH_RESET); | ||
353 | AddrTable[0] = MASTER_CONTROL_ADDR; | ||
354 | ByteTable[0] |= state->config->AgcMasterByte; | ||
355 | |||
356 | mxl5005s_writeregs(fe, AddrTable, ByteTable, 1); | ||
357 | |||
358 | /* Tuner RF frequency setting stage 1 */ | ||
359 | MXL_TuneRF(fe, RfFreqHz); | ||
360 | |||
361 | MXL_ControlRead(fe, IF_DIVVAL, &IfDivval); | ||
362 | |||
363 | MXL_ControlWrite(fe, SEQ_FSM_PULSE, 0); | ||
364 | MXL_ControlWrite(fe, SEQ_EXTPOWERUP, 1); | ||
365 | MXL_ControlWrite(fe, IF_DIVVAL, 8); | ||
366 | MXL_GetCHRegister(fe, AddrTable, ByteTable, &TableLen); | ||
367 | |||
368 | MXL_GetMasterControl(&MasterControlByte, MC_LOAD_START); | ||
369 | AddrTable[TableLen] = MASTER_CONTROL_ADDR ; | ||
370 | ByteTable[TableLen] = MasterControlByte | | ||
371 | state->config->AgcMasterByte; | ||
372 | TableLen += 1; | ||
373 | |||
374 | mxl5005s_writeregs(fe, AddrTable, ByteTable, TableLen); | ||
375 | |||
376 | /* Wait 30 ms. */ | ||
377 | msleep(150); | ||
378 | |||
379 | /* Tuner RF frequency setting stage 2 */ | ||
380 | MXL_ControlWrite(fe, SEQ_FSM_PULSE, 1); | ||
381 | MXL_ControlWrite(fe, IF_DIVVAL, IfDivval); | ||
382 | MXL_GetCHRegister_ZeroIF(fe, AddrTable, ByteTable, &TableLen); | ||
383 | |||
384 | MXL_GetMasterControl(&MasterControlByte, MC_LOAD_START); | ||
385 | AddrTable[TableLen] = MASTER_CONTROL_ADDR ; | ||
386 | ByteTable[TableLen] = MasterControlByte | | ||
387 | state->config->AgcMasterByte ; | ||
388 | TableLen += 1; | ||
389 | |||
390 | mxl5005s_writeregs(fe, AddrTable, ByteTable, TableLen); | ||
391 | |||
392 | msleep(100); | ||
393 | |||
394 | return 0; | ||
395 | } | ||
396 | /* End: Custom code taken from the Realtek driver */ | ||
397 | |||
398 | /* ---------------------------------------------------------------- | ||
399 | * Begin: Reference driver code found in the Realtek driver. | ||
400 | * Copyright (C) 2008 MaxLinear | ||
401 | */ | ||
402 | static u16 MXL5005_RegisterInit(struct dvb_frontend *fe) | ||
403 | { | ||
404 | struct mxl5005s_state *state = fe->tuner_priv; | ||
405 | state->TunerRegs_Num = TUNER_REGS_NUM ; | ||
406 | |||
407 | state->TunerRegs[0].Reg_Num = 9 ; | ||
408 | state->TunerRegs[0].Reg_Val = 0x40 ; | ||
409 | |||
410 | state->TunerRegs[1].Reg_Num = 11 ; | ||
411 | state->TunerRegs[1].Reg_Val = 0x19 ; | ||
412 | |||
413 | state->TunerRegs[2].Reg_Num = 12 ; | ||
414 | state->TunerRegs[2].Reg_Val = 0x60 ; | ||
415 | |||
416 | state->TunerRegs[3].Reg_Num = 13 ; | ||
417 | state->TunerRegs[3].Reg_Val = 0x00 ; | ||
418 | |||
419 | state->TunerRegs[4].Reg_Num = 14 ; | ||
420 | state->TunerRegs[4].Reg_Val = 0x00 ; | ||
421 | |||
422 | state->TunerRegs[5].Reg_Num = 15 ; | ||
423 | state->TunerRegs[5].Reg_Val = 0xC0 ; | ||
424 | |||
425 | state->TunerRegs[6].Reg_Num = 16 ; | ||
426 | state->TunerRegs[6].Reg_Val = 0x00 ; | ||
427 | |||
428 | state->TunerRegs[7].Reg_Num = 17 ; | ||
429 | state->TunerRegs[7].Reg_Val = 0x00 ; | ||
430 | |||
431 | state->TunerRegs[8].Reg_Num = 18 ; | ||
432 | state->TunerRegs[8].Reg_Val = 0x00 ; | ||
433 | |||
434 | state->TunerRegs[9].Reg_Num = 19 ; | ||
435 | state->TunerRegs[9].Reg_Val = 0x34 ; | ||
436 | |||
437 | state->TunerRegs[10].Reg_Num = 21 ; | ||
438 | state->TunerRegs[10].Reg_Val = 0x00 ; | ||
439 | |||
440 | state->TunerRegs[11].Reg_Num = 22 ; | ||
441 | state->TunerRegs[11].Reg_Val = 0x6B ; | ||
442 | |||
443 | state->TunerRegs[12].Reg_Num = 23 ; | ||
444 | state->TunerRegs[12].Reg_Val = 0x35 ; | ||
445 | |||
446 | state->TunerRegs[13].Reg_Num = 24 ; | ||
447 | state->TunerRegs[13].Reg_Val = 0x70 ; | ||
448 | |||
449 | state->TunerRegs[14].Reg_Num = 25 ; | ||
450 | state->TunerRegs[14].Reg_Val = 0x3E ; | ||
451 | |||
452 | state->TunerRegs[15].Reg_Num = 26 ; | ||
453 | state->TunerRegs[15].Reg_Val = 0x82 ; | ||
454 | |||
455 | state->TunerRegs[16].Reg_Num = 31 ; | ||
456 | state->TunerRegs[16].Reg_Val = 0x00 ; | ||
457 | |||
458 | state->TunerRegs[17].Reg_Num = 32 ; | ||
459 | state->TunerRegs[17].Reg_Val = 0x40 ; | ||
460 | |||
461 | state->TunerRegs[18].Reg_Num = 33 ; | ||
462 | state->TunerRegs[18].Reg_Val = 0x53 ; | ||
463 | |||
464 | state->TunerRegs[19].Reg_Num = 34 ; | ||
465 | state->TunerRegs[19].Reg_Val = 0x81 ; | ||
466 | |||
467 | state->TunerRegs[20].Reg_Num = 35 ; | ||
468 | state->TunerRegs[20].Reg_Val = 0xC9 ; | ||
469 | |||
470 | state->TunerRegs[21].Reg_Num = 36 ; | ||
471 | state->TunerRegs[21].Reg_Val = 0x01 ; | ||
472 | |||
473 | state->TunerRegs[22].Reg_Num = 37 ; | ||
474 | state->TunerRegs[22].Reg_Val = 0x00 ; | ||
475 | |||
476 | state->TunerRegs[23].Reg_Num = 41 ; | ||
477 | state->TunerRegs[23].Reg_Val = 0x00 ; | ||
478 | |||
479 | state->TunerRegs[24].Reg_Num = 42 ; | ||
480 | state->TunerRegs[24].Reg_Val = 0xF8 ; | ||
481 | |||
482 | state->TunerRegs[25].Reg_Num = 43 ; | ||
483 | state->TunerRegs[25].Reg_Val = 0x43 ; | ||
484 | |||
485 | state->TunerRegs[26].Reg_Num = 44 ; | ||
486 | state->TunerRegs[26].Reg_Val = 0x20 ; | ||
487 | |||
488 | state->TunerRegs[27].Reg_Num = 45 ; | ||
489 | state->TunerRegs[27].Reg_Val = 0x80 ; | ||
490 | |||
491 | state->TunerRegs[28].Reg_Num = 46 ; | ||
492 | state->TunerRegs[28].Reg_Val = 0x88 ; | ||
493 | |||
494 | state->TunerRegs[29].Reg_Num = 47 ; | ||
495 | state->TunerRegs[29].Reg_Val = 0x86 ; | ||
496 | |||
497 | state->TunerRegs[30].Reg_Num = 48 ; | ||
498 | state->TunerRegs[30].Reg_Val = 0x00 ; | ||
499 | |||
500 | state->TunerRegs[31].Reg_Num = 49 ; | ||
501 | state->TunerRegs[31].Reg_Val = 0x00 ; | ||
502 | |||
503 | state->TunerRegs[32].Reg_Num = 53 ; | ||
504 | state->TunerRegs[32].Reg_Val = 0x94 ; | ||
505 | |||
506 | state->TunerRegs[33].Reg_Num = 54 ; | ||
507 | state->TunerRegs[33].Reg_Val = 0xFA ; | ||
508 | |||
509 | state->TunerRegs[34].Reg_Num = 55 ; | ||
510 | state->TunerRegs[34].Reg_Val = 0x92 ; | ||
511 | |||
512 | state->TunerRegs[35].Reg_Num = 56 ; | ||
513 | state->TunerRegs[35].Reg_Val = 0x80 ; | ||
514 | |||
515 | state->TunerRegs[36].Reg_Num = 57 ; | ||
516 | state->TunerRegs[36].Reg_Val = 0x41 ; | ||
517 | |||
518 | state->TunerRegs[37].Reg_Num = 58 ; | ||
519 | state->TunerRegs[37].Reg_Val = 0xDB ; | ||
520 | |||
521 | state->TunerRegs[38].Reg_Num = 59 ; | ||
522 | state->TunerRegs[38].Reg_Val = 0x00 ; | ||
523 | |||
524 | state->TunerRegs[39].Reg_Num = 60 ; | ||
525 | state->TunerRegs[39].Reg_Val = 0x00 ; | ||
526 | |||
527 | state->TunerRegs[40].Reg_Num = 61 ; | ||
528 | state->TunerRegs[40].Reg_Val = 0x00 ; | ||
529 | |||
530 | state->TunerRegs[41].Reg_Num = 62 ; | ||
531 | state->TunerRegs[41].Reg_Val = 0x00 ; | ||
532 | |||
533 | state->TunerRegs[42].Reg_Num = 65 ; | ||
534 | state->TunerRegs[42].Reg_Val = 0xF8 ; | ||
535 | |||
536 | state->TunerRegs[43].Reg_Num = 66 ; | ||
537 | state->TunerRegs[43].Reg_Val = 0xE4 ; | ||
538 | |||
539 | state->TunerRegs[44].Reg_Num = 67 ; | ||
540 | state->TunerRegs[44].Reg_Val = 0x90 ; | ||
541 | |||
542 | state->TunerRegs[45].Reg_Num = 68 ; | ||
543 | state->TunerRegs[45].Reg_Val = 0xC0 ; | ||
544 | |||
545 | state->TunerRegs[46].Reg_Num = 69 ; | ||
546 | state->TunerRegs[46].Reg_Val = 0x01 ; | ||
547 | |||
548 | state->TunerRegs[47].Reg_Num = 70 ; | ||
549 | state->TunerRegs[47].Reg_Val = 0x50 ; | ||
550 | |||
551 | state->TunerRegs[48].Reg_Num = 71 ; | ||
552 | state->TunerRegs[48].Reg_Val = 0x06 ; | ||
553 | |||
554 | state->TunerRegs[49].Reg_Num = 72 ; | ||
555 | state->TunerRegs[49].Reg_Val = 0x00 ; | ||
556 | |||
557 | state->TunerRegs[50].Reg_Num = 73 ; | ||
558 | state->TunerRegs[50].Reg_Val = 0x20 ; | ||
559 | |||
560 | state->TunerRegs[51].Reg_Num = 76 ; | ||
561 | state->TunerRegs[51].Reg_Val = 0xBB ; | ||
562 | |||
563 | state->TunerRegs[52].Reg_Num = 77 ; | ||
564 | state->TunerRegs[52].Reg_Val = 0x13 ; | ||
565 | |||
566 | state->TunerRegs[53].Reg_Num = 81 ; | ||
567 | state->TunerRegs[53].Reg_Val = 0x04 ; | ||
568 | |||
569 | state->TunerRegs[54].Reg_Num = 82 ; | ||
570 | state->TunerRegs[54].Reg_Val = 0x75 ; | ||
571 | |||
572 | state->TunerRegs[55].Reg_Num = 83 ; | ||
573 | state->TunerRegs[55].Reg_Val = 0x00 ; | ||
574 | |||
575 | state->TunerRegs[56].Reg_Num = 84 ; | ||
576 | state->TunerRegs[56].Reg_Val = 0x00 ; | ||
577 | |||
578 | state->TunerRegs[57].Reg_Num = 85 ; | ||
579 | state->TunerRegs[57].Reg_Val = 0x00 ; | ||
580 | |||
581 | state->TunerRegs[58].Reg_Num = 91 ; | ||
582 | state->TunerRegs[58].Reg_Val = 0x70 ; | ||
583 | |||
584 | state->TunerRegs[59].Reg_Num = 92 ; | ||
585 | state->TunerRegs[59].Reg_Val = 0x00 ; | ||
586 | |||
587 | state->TunerRegs[60].Reg_Num = 93 ; | ||
588 | state->TunerRegs[60].Reg_Val = 0x00 ; | ||
589 | |||
590 | state->TunerRegs[61].Reg_Num = 94 ; | ||
591 | state->TunerRegs[61].Reg_Val = 0x00 ; | ||
592 | |||
593 | state->TunerRegs[62].Reg_Num = 95 ; | ||
594 | state->TunerRegs[62].Reg_Val = 0x0C ; | ||
595 | |||
596 | state->TunerRegs[63].Reg_Num = 96 ; | ||
597 | state->TunerRegs[63].Reg_Val = 0x00 ; | ||
598 | |||
599 | state->TunerRegs[64].Reg_Num = 97 ; | ||
600 | state->TunerRegs[64].Reg_Val = 0x00 ; | ||
601 | |||
602 | state->TunerRegs[65].Reg_Num = 98 ; | ||
603 | state->TunerRegs[65].Reg_Val = 0xE2 ; | ||
604 | |||
605 | state->TunerRegs[66].Reg_Num = 99 ; | ||
606 | state->TunerRegs[66].Reg_Val = 0x00 ; | ||
607 | |||
608 | state->TunerRegs[67].Reg_Num = 100 ; | ||
609 | state->TunerRegs[67].Reg_Val = 0x00 ; | ||
610 | |||
611 | state->TunerRegs[68].Reg_Num = 101 ; | ||
612 | state->TunerRegs[68].Reg_Val = 0x12 ; | ||
613 | |||
614 | state->TunerRegs[69].Reg_Num = 102 ; | ||
615 | state->TunerRegs[69].Reg_Val = 0x80 ; | ||
616 | |||
617 | state->TunerRegs[70].Reg_Num = 103 ; | ||
618 | state->TunerRegs[70].Reg_Val = 0x32 ; | ||
619 | |||
620 | state->TunerRegs[71].Reg_Num = 104 ; | ||
621 | state->TunerRegs[71].Reg_Val = 0xB4 ; | ||
622 | |||
623 | state->TunerRegs[72].Reg_Num = 105 ; | ||
624 | state->TunerRegs[72].Reg_Val = 0x60 ; | ||
625 | |||
626 | state->TunerRegs[73].Reg_Num = 106 ; | ||
627 | state->TunerRegs[73].Reg_Val = 0x83 ; | ||
628 | |||
629 | state->TunerRegs[74].Reg_Num = 107 ; | ||
630 | state->TunerRegs[74].Reg_Val = 0x84 ; | ||
631 | |||
632 | state->TunerRegs[75].Reg_Num = 108 ; | ||
633 | state->TunerRegs[75].Reg_Val = 0x9C ; | ||
634 | |||
635 | state->TunerRegs[76].Reg_Num = 109 ; | ||
636 | state->TunerRegs[76].Reg_Val = 0x02 ; | ||
637 | |||
638 | state->TunerRegs[77].Reg_Num = 110 ; | ||
639 | state->TunerRegs[77].Reg_Val = 0x81 ; | ||
640 | |||
641 | state->TunerRegs[78].Reg_Num = 111 ; | ||
642 | state->TunerRegs[78].Reg_Val = 0xC0 ; | ||
643 | |||
644 | state->TunerRegs[79].Reg_Num = 112 ; | ||
645 | state->TunerRegs[79].Reg_Val = 0x10 ; | ||
646 | |||
647 | state->TunerRegs[80].Reg_Num = 131 ; | ||
648 | state->TunerRegs[80].Reg_Val = 0x8A ; | ||
649 | |||
650 | state->TunerRegs[81].Reg_Num = 132 ; | ||
651 | state->TunerRegs[81].Reg_Val = 0x10 ; | ||
652 | |||
653 | state->TunerRegs[82].Reg_Num = 133 ; | ||
654 | state->TunerRegs[82].Reg_Val = 0x24 ; | ||
655 | |||
656 | state->TunerRegs[83].Reg_Num = 134 ; | ||
657 | state->TunerRegs[83].Reg_Val = 0x00 ; | ||
658 | |||
659 | state->TunerRegs[84].Reg_Num = 135 ; | ||
660 | state->TunerRegs[84].Reg_Val = 0x00 ; | ||
661 | |||
662 | state->TunerRegs[85].Reg_Num = 136 ; | ||
663 | state->TunerRegs[85].Reg_Val = 0x7E ; | ||
664 | |||
665 | state->TunerRegs[86].Reg_Num = 137 ; | ||
666 | state->TunerRegs[86].Reg_Val = 0x40 ; | ||
667 | |||
668 | state->TunerRegs[87].Reg_Num = 138 ; | ||
669 | state->TunerRegs[87].Reg_Val = 0x38 ; | ||
670 | |||
671 | state->TunerRegs[88].Reg_Num = 146 ; | ||
672 | state->TunerRegs[88].Reg_Val = 0xF6 ; | ||
673 | |||
674 | state->TunerRegs[89].Reg_Num = 147 ; | ||
675 | state->TunerRegs[89].Reg_Val = 0x1A ; | ||
676 | |||
677 | state->TunerRegs[90].Reg_Num = 148 ; | ||
678 | state->TunerRegs[90].Reg_Val = 0x62 ; | ||
679 | |||
680 | state->TunerRegs[91].Reg_Num = 149 ; | ||
681 | state->TunerRegs[91].Reg_Val = 0x33 ; | ||
682 | |||
683 | state->TunerRegs[92].Reg_Num = 150 ; | ||
684 | state->TunerRegs[92].Reg_Val = 0x80 ; | ||
685 | |||
686 | state->TunerRegs[93].Reg_Num = 156 ; | ||
687 | state->TunerRegs[93].Reg_Val = 0x56 ; | ||
688 | |||
689 | state->TunerRegs[94].Reg_Num = 157 ; | ||
690 | state->TunerRegs[94].Reg_Val = 0x17 ; | ||
691 | |||
692 | state->TunerRegs[95].Reg_Num = 158 ; | ||
693 | state->TunerRegs[95].Reg_Val = 0xA9 ; | ||
694 | |||
695 | state->TunerRegs[96].Reg_Num = 159 ; | ||
696 | state->TunerRegs[96].Reg_Val = 0x00 ; | ||
697 | |||
698 | state->TunerRegs[97].Reg_Num = 160 ; | ||
699 | state->TunerRegs[97].Reg_Val = 0x00 ; | ||
700 | |||
701 | state->TunerRegs[98].Reg_Num = 161 ; | ||
702 | state->TunerRegs[98].Reg_Val = 0x00 ; | ||
703 | |||
704 | state->TunerRegs[99].Reg_Num = 162 ; | ||
705 | state->TunerRegs[99].Reg_Val = 0x40 ; | ||
706 | |||
707 | state->TunerRegs[100].Reg_Num = 166 ; | ||
708 | state->TunerRegs[100].Reg_Val = 0xAE ; | ||
709 | |||
710 | state->TunerRegs[101].Reg_Num = 167 ; | ||
711 | state->TunerRegs[101].Reg_Val = 0x1B ; | ||
712 | |||
713 | state->TunerRegs[102].Reg_Num = 168 ; | ||
714 | state->TunerRegs[102].Reg_Val = 0xF2 ; | ||
715 | |||
716 | state->TunerRegs[103].Reg_Num = 195 ; | ||
717 | state->TunerRegs[103].Reg_Val = 0x00 ; | ||
718 | |||
719 | return 0 ; | ||
720 | } | ||
721 | |||
722 | static u16 MXL5005_ControlInit(struct dvb_frontend *fe) | ||
723 | { | ||
724 | struct mxl5005s_state *state = fe->tuner_priv; | ||
725 | state->Init_Ctrl_Num = INITCTRL_NUM; | ||
726 | |||
727 | state->Init_Ctrl[0].Ctrl_Num = DN_IQTN_AMP_CUT ; | ||
728 | state->Init_Ctrl[0].size = 1 ; | ||
729 | state->Init_Ctrl[0].addr[0] = 73; | ||
730 | state->Init_Ctrl[0].bit[0] = 7; | ||
731 | state->Init_Ctrl[0].val[0] = 0; | ||
732 | |||
733 | state->Init_Ctrl[1].Ctrl_Num = BB_MODE ; | ||
734 | state->Init_Ctrl[1].size = 1 ; | ||
735 | state->Init_Ctrl[1].addr[0] = 53; | ||
736 | state->Init_Ctrl[1].bit[0] = 2; | ||
737 | state->Init_Ctrl[1].val[0] = 1; | ||
738 | |||
739 | state->Init_Ctrl[2].Ctrl_Num = BB_BUF ; | ||
740 | state->Init_Ctrl[2].size = 2 ; | ||
741 | state->Init_Ctrl[2].addr[0] = 53; | ||
742 | state->Init_Ctrl[2].bit[0] = 1; | ||
743 | state->Init_Ctrl[2].val[0] = 0; | ||
744 | state->Init_Ctrl[2].addr[1] = 57; | ||
745 | state->Init_Ctrl[2].bit[1] = 0; | ||
746 | state->Init_Ctrl[2].val[1] = 1; | ||
747 | |||
748 | state->Init_Ctrl[3].Ctrl_Num = BB_BUF_OA ; | ||
749 | state->Init_Ctrl[3].size = 1 ; | ||
750 | state->Init_Ctrl[3].addr[0] = 53; | ||
751 | state->Init_Ctrl[3].bit[0] = 0; | ||
752 | state->Init_Ctrl[3].val[0] = 0; | ||
753 | |||
754 | state->Init_Ctrl[4].Ctrl_Num = BB_ALPF_BANDSELECT ; | ||
755 | state->Init_Ctrl[4].size = 3 ; | ||
756 | state->Init_Ctrl[4].addr[0] = 53; | ||
757 | state->Init_Ctrl[4].bit[0] = 5; | ||
758 | state->Init_Ctrl[4].val[0] = 0; | ||
759 | state->Init_Ctrl[4].addr[1] = 53; | ||
760 | state->Init_Ctrl[4].bit[1] = 6; | ||
761 | state->Init_Ctrl[4].val[1] = 0; | ||
762 | state->Init_Ctrl[4].addr[2] = 53; | ||
763 | state->Init_Ctrl[4].bit[2] = 7; | ||
764 | state->Init_Ctrl[4].val[2] = 1; | ||
765 | |||
766 | state->Init_Ctrl[5].Ctrl_Num = BB_IQSWAP ; | ||
767 | state->Init_Ctrl[5].size = 1 ; | ||
768 | state->Init_Ctrl[5].addr[0] = 59; | ||
769 | state->Init_Ctrl[5].bit[0] = 0; | ||
770 | state->Init_Ctrl[5].val[0] = 0; | ||
771 | |||
772 | state->Init_Ctrl[6].Ctrl_Num = BB_DLPF_BANDSEL ; | ||
773 | state->Init_Ctrl[6].size = 2 ; | ||
774 | state->Init_Ctrl[6].addr[0] = 53; | ||
775 | state->Init_Ctrl[6].bit[0] = 3; | ||
776 | state->Init_Ctrl[6].val[0] = 0; | ||
777 | state->Init_Ctrl[6].addr[1] = 53; | ||
778 | state->Init_Ctrl[6].bit[1] = 4; | ||
779 | state->Init_Ctrl[6].val[1] = 1; | ||
780 | |||
781 | state->Init_Ctrl[7].Ctrl_Num = RFSYN_CHP_GAIN ; | ||
782 | state->Init_Ctrl[7].size = 4 ; | ||
783 | state->Init_Ctrl[7].addr[0] = 22; | ||
784 | state->Init_Ctrl[7].bit[0] = 4; | ||
785 | state->Init_Ctrl[7].val[0] = 0; | ||
786 | state->Init_Ctrl[7].addr[1] = 22; | ||
787 | state->Init_Ctrl[7].bit[1] = 5; | ||
788 | state->Init_Ctrl[7].val[1] = 1; | ||
789 | state->Init_Ctrl[7].addr[2] = 22; | ||
790 | state->Init_Ctrl[7].bit[2] = 6; | ||
791 | state->Init_Ctrl[7].val[2] = 1; | ||
792 | state->Init_Ctrl[7].addr[3] = 22; | ||
793 | state->Init_Ctrl[7].bit[3] = 7; | ||
794 | state->Init_Ctrl[7].val[3] = 0; | ||
795 | |||
796 | state->Init_Ctrl[8].Ctrl_Num = RFSYN_EN_CHP_HIGAIN ; | ||
797 | state->Init_Ctrl[8].size = 1 ; | ||
798 | state->Init_Ctrl[8].addr[0] = 22; | ||
799 | state->Init_Ctrl[8].bit[0] = 2; | ||
800 | state->Init_Ctrl[8].val[0] = 0; | ||
801 | |||
802 | state->Init_Ctrl[9].Ctrl_Num = AGC_IF ; | ||
803 | state->Init_Ctrl[9].size = 4 ; | ||
804 | state->Init_Ctrl[9].addr[0] = 76; | ||
805 | state->Init_Ctrl[9].bit[0] = 0; | ||
806 | state->Init_Ctrl[9].val[0] = 1; | ||
807 | state->Init_Ctrl[9].addr[1] = 76; | ||
808 | state->Init_Ctrl[9].bit[1] = 1; | ||
809 | state->Init_Ctrl[9].val[1] = 1; | ||
810 | state->Init_Ctrl[9].addr[2] = 76; | ||
811 | state->Init_Ctrl[9].bit[2] = 2; | ||
812 | state->Init_Ctrl[9].val[2] = 0; | ||
813 | state->Init_Ctrl[9].addr[3] = 76; | ||
814 | state->Init_Ctrl[9].bit[3] = 3; | ||
815 | state->Init_Ctrl[9].val[3] = 1; | ||
816 | |||
817 | state->Init_Ctrl[10].Ctrl_Num = AGC_RF ; | ||
818 | state->Init_Ctrl[10].size = 4 ; | ||
819 | state->Init_Ctrl[10].addr[0] = 76; | ||
820 | state->Init_Ctrl[10].bit[0] = 4; | ||
821 | state->Init_Ctrl[10].val[0] = 1; | ||
822 | state->Init_Ctrl[10].addr[1] = 76; | ||
823 | state->Init_Ctrl[10].bit[1] = 5; | ||
824 | state->Init_Ctrl[10].val[1] = 1; | ||
825 | state->Init_Ctrl[10].addr[2] = 76; | ||
826 | state->Init_Ctrl[10].bit[2] = 6; | ||
827 | state->Init_Ctrl[10].val[2] = 0; | ||
828 | state->Init_Ctrl[10].addr[3] = 76; | ||
829 | state->Init_Ctrl[10].bit[3] = 7; | ||
830 | state->Init_Ctrl[10].val[3] = 1; | ||
831 | |||
832 | state->Init_Ctrl[11].Ctrl_Num = IF_DIVVAL ; | ||
833 | state->Init_Ctrl[11].size = 5 ; | ||
834 | state->Init_Ctrl[11].addr[0] = 43; | ||
835 | state->Init_Ctrl[11].bit[0] = 3; | ||
836 | state->Init_Ctrl[11].val[0] = 0; | ||
837 | state->Init_Ctrl[11].addr[1] = 43; | ||
838 | state->Init_Ctrl[11].bit[1] = 4; | ||
839 | state->Init_Ctrl[11].val[1] = 0; | ||
840 | state->Init_Ctrl[11].addr[2] = 43; | ||
841 | state->Init_Ctrl[11].bit[2] = 5; | ||
842 | state->Init_Ctrl[11].val[2] = 0; | ||
843 | state->Init_Ctrl[11].addr[3] = 43; | ||
844 | state->Init_Ctrl[11].bit[3] = 6; | ||
845 | state->Init_Ctrl[11].val[3] = 1; | ||
846 | state->Init_Ctrl[11].addr[4] = 43; | ||
847 | state->Init_Ctrl[11].bit[4] = 7; | ||
848 | state->Init_Ctrl[11].val[4] = 0; | ||
849 | |||
850 | state->Init_Ctrl[12].Ctrl_Num = IF_VCO_BIAS ; | ||
851 | state->Init_Ctrl[12].size = 6 ; | ||
852 | state->Init_Ctrl[12].addr[0] = 44; | ||
853 | state->Init_Ctrl[12].bit[0] = 2; | ||
854 | state->Init_Ctrl[12].val[0] = 0; | ||
855 | state->Init_Ctrl[12].addr[1] = 44; | ||
856 | state->Init_Ctrl[12].bit[1] = 3; | ||
857 | state->Init_Ctrl[12].val[1] = 0; | ||
858 | state->Init_Ctrl[12].addr[2] = 44; | ||
859 | state->Init_Ctrl[12].bit[2] = 4; | ||
860 | state->Init_Ctrl[12].val[2] = 0; | ||
861 | state->Init_Ctrl[12].addr[3] = 44; | ||
862 | state->Init_Ctrl[12].bit[3] = 5; | ||
863 | state->Init_Ctrl[12].val[3] = 1; | ||
864 | state->Init_Ctrl[12].addr[4] = 44; | ||
865 | state->Init_Ctrl[12].bit[4] = 6; | ||
866 | state->Init_Ctrl[12].val[4] = 0; | ||
867 | state->Init_Ctrl[12].addr[5] = 44; | ||
868 | state->Init_Ctrl[12].bit[5] = 7; | ||
869 | state->Init_Ctrl[12].val[5] = 0; | ||
870 | |||
871 | state->Init_Ctrl[13].Ctrl_Num = CHCAL_INT_MOD_IF ; | ||
872 | state->Init_Ctrl[13].size = 7 ; | ||
873 | state->Init_Ctrl[13].addr[0] = 11; | ||
874 | state->Init_Ctrl[13].bit[0] = 0; | ||
875 | state->Init_Ctrl[13].val[0] = 1; | ||
876 | state->Init_Ctrl[13].addr[1] = 11; | ||
877 | state->Init_Ctrl[13].bit[1] = 1; | ||
878 | state->Init_Ctrl[13].val[1] = 0; | ||
879 | state->Init_Ctrl[13].addr[2] = 11; | ||
880 | state->Init_Ctrl[13].bit[2] = 2; | ||
881 | state->Init_Ctrl[13].val[2] = 0; | ||
882 | state->Init_Ctrl[13].addr[3] = 11; | ||
883 | state->Init_Ctrl[13].bit[3] = 3; | ||
884 | state->Init_Ctrl[13].val[3] = 1; | ||
885 | state->Init_Ctrl[13].addr[4] = 11; | ||
886 | state->Init_Ctrl[13].bit[4] = 4; | ||
887 | state->Init_Ctrl[13].val[4] = 1; | ||
888 | state->Init_Ctrl[13].addr[5] = 11; | ||
889 | state->Init_Ctrl[13].bit[5] = 5; | ||
890 | state->Init_Ctrl[13].val[5] = 0; | ||
891 | state->Init_Ctrl[13].addr[6] = 11; | ||
892 | state->Init_Ctrl[13].bit[6] = 6; | ||
893 | state->Init_Ctrl[13].val[6] = 0; | ||
894 | |||
895 | state->Init_Ctrl[14].Ctrl_Num = CHCAL_FRAC_MOD_IF ; | ||
896 | state->Init_Ctrl[14].size = 16 ; | ||
897 | state->Init_Ctrl[14].addr[0] = 13; | ||
898 | state->Init_Ctrl[14].bit[0] = 0; | ||
899 | state->Init_Ctrl[14].val[0] = 0; | ||
900 | state->Init_Ctrl[14].addr[1] = 13; | ||
901 | state->Init_Ctrl[14].bit[1] = 1; | ||
902 | state->Init_Ctrl[14].val[1] = 0; | ||
903 | state->Init_Ctrl[14].addr[2] = 13; | ||
904 | state->Init_Ctrl[14].bit[2] = 2; | ||
905 | state->Init_Ctrl[14].val[2] = 0; | ||
906 | state->Init_Ctrl[14].addr[3] = 13; | ||
907 | state->Init_Ctrl[14].bit[3] = 3; | ||
908 | state->Init_Ctrl[14].val[3] = 0; | ||
909 | state->Init_Ctrl[14].addr[4] = 13; | ||
910 | state->Init_Ctrl[14].bit[4] = 4; | ||
911 | state->Init_Ctrl[14].val[4] = 0; | ||
912 | state->Init_Ctrl[14].addr[5] = 13; | ||
913 | state->Init_Ctrl[14].bit[5] = 5; | ||
914 | state->Init_Ctrl[14].val[5] = 0; | ||
915 | state->Init_Ctrl[14].addr[6] = 13; | ||
916 | state->Init_Ctrl[14].bit[6] = 6; | ||
917 | state->Init_Ctrl[14].val[6] = 0; | ||
918 | state->Init_Ctrl[14].addr[7] = 13; | ||
919 | state->Init_Ctrl[14].bit[7] = 7; | ||
920 | state->Init_Ctrl[14].val[7] = 0; | ||
921 | state->Init_Ctrl[14].addr[8] = 12; | ||
922 | state->Init_Ctrl[14].bit[8] = 0; | ||
923 | state->Init_Ctrl[14].val[8] = 0; | ||
924 | state->Init_Ctrl[14].addr[9] = 12; | ||
925 | state->Init_Ctrl[14].bit[9] = 1; | ||
926 | state->Init_Ctrl[14].val[9] = 0; | ||
927 | state->Init_Ctrl[14].addr[10] = 12; | ||
928 | state->Init_Ctrl[14].bit[10] = 2; | ||
929 | state->Init_Ctrl[14].val[10] = 0; | ||
930 | state->Init_Ctrl[14].addr[11] = 12; | ||
931 | state->Init_Ctrl[14].bit[11] = 3; | ||
932 | state->Init_Ctrl[14].val[11] = 0; | ||
933 | state->Init_Ctrl[14].addr[12] = 12; | ||
934 | state->Init_Ctrl[14].bit[12] = 4; | ||
935 | state->Init_Ctrl[14].val[12] = 0; | ||
936 | state->Init_Ctrl[14].addr[13] = 12; | ||
937 | state->Init_Ctrl[14].bit[13] = 5; | ||
938 | state->Init_Ctrl[14].val[13] = 1; | ||
939 | state->Init_Ctrl[14].addr[14] = 12; | ||
940 | state->Init_Ctrl[14].bit[14] = 6; | ||
941 | state->Init_Ctrl[14].val[14] = 1; | ||
942 | state->Init_Ctrl[14].addr[15] = 12; | ||
943 | state->Init_Ctrl[14].bit[15] = 7; | ||
944 | state->Init_Ctrl[14].val[15] = 0; | ||
945 | |||
946 | state->Init_Ctrl[15].Ctrl_Num = DRV_RES_SEL ; | ||
947 | state->Init_Ctrl[15].size = 3 ; | ||
948 | state->Init_Ctrl[15].addr[0] = 147; | ||
949 | state->Init_Ctrl[15].bit[0] = 2; | ||
950 | state->Init_Ctrl[15].val[0] = 0; | ||
951 | state->Init_Ctrl[15].addr[1] = 147; | ||
952 | state->Init_Ctrl[15].bit[1] = 3; | ||
953 | state->Init_Ctrl[15].val[1] = 1; | ||
954 | state->Init_Ctrl[15].addr[2] = 147; | ||
955 | state->Init_Ctrl[15].bit[2] = 4; | ||
956 | state->Init_Ctrl[15].val[2] = 1; | ||
957 | |||
958 | state->Init_Ctrl[16].Ctrl_Num = I_DRIVER ; | ||
959 | state->Init_Ctrl[16].size = 2 ; | ||
960 | state->Init_Ctrl[16].addr[0] = 147; | ||
961 | state->Init_Ctrl[16].bit[0] = 0; | ||
962 | state->Init_Ctrl[16].val[0] = 0; | ||
963 | state->Init_Ctrl[16].addr[1] = 147; | ||
964 | state->Init_Ctrl[16].bit[1] = 1; | ||
965 | state->Init_Ctrl[16].val[1] = 1; | ||
966 | |||
967 | state->Init_Ctrl[17].Ctrl_Num = EN_AAF ; | ||
968 | state->Init_Ctrl[17].size = 1 ; | ||
969 | state->Init_Ctrl[17].addr[0] = 147; | ||
970 | state->Init_Ctrl[17].bit[0] = 7; | ||
971 | state->Init_Ctrl[17].val[0] = 0; | ||
972 | |||
973 | state->Init_Ctrl[18].Ctrl_Num = EN_3P ; | ||
974 | state->Init_Ctrl[18].size = 1 ; | ||
975 | state->Init_Ctrl[18].addr[0] = 147; | ||
976 | state->Init_Ctrl[18].bit[0] = 6; | ||
977 | state->Init_Ctrl[18].val[0] = 0; | ||
978 | |||
979 | state->Init_Ctrl[19].Ctrl_Num = EN_AUX_3P ; | ||
980 | state->Init_Ctrl[19].size = 1 ; | ||
981 | state->Init_Ctrl[19].addr[0] = 156; | ||
982 | state->Init_Ctrl[19].bit[0] = 0; | ||
983 | state->Init_Ctrl[19].val[0] = 0; | ||
984 | |||
985 | state->Init_Ctrl[20].Ctrl_Num = SEL_AAF_BAND ; | ||
986 | state->Init_Ctrl[20].size = 1 ; | ||
987 | state->Init_Ctrl[20].addr[0] = 147; | ||
988 | state->Init_Ctrl[20].bit[0] = 5; | ||
989 | state->Init_Ctrl[20].val[0] = 0; | ||
990 | |||
991 | state->Init_Ctrl[21].Ctrl_Num = SEQ_ENCLK16_CLK_OUT ; | ||
992 | state->Init_Ctrl[21].size = 1 ; | ||
993 | state->Init_Ctrl[21].addr[0] = 137; | ||
994 | state->Init_Ctrl[21].bit[0] = 4; | ||
995 | state->Init_Ctrl[21].val[0] = 0; | ||
996 | |||
997 | state->Init_Ctrl[22].Ctrl_Num = SEQ_SEL4_16B ; | ||
998 | state->Init_Ctrl[22].size = 1 ; | ||
999 | state->Init_Ctrl[22].addr[0] = 137; | ||
1000 | state->Init_Ctrl[22].bit[0] = 7; | ||
1001 | state->Init_Ctrl[22].val[0] = 0; | ||
1002 | |||
1003 | state->Init_Ctrl[23].Ctrl_Num = XTAL_CAPSELECT ; | ||
1004 | state->Init_Ctrl[23].size = 1 ; | ||
1005 | state->Init_Ctrl[23].addr[0] = 91; | ||
1006 | state->Init_Ctrl[23].bit[0] = 5; | ||
1007 | state->Init_Ctrl[23].val[0] = 1; | ||
1008 | |||
1009 | state->Init_Ctrl[24].Ctrl_Num = IF_SEL_DBL ; | ||
1010 | state->Init_Ctrl[24].size = 1 ; | ||
1011 | state->Init_Ctrl[24].addr[0] = 43; | ||
1012 | state->Init_Ctrl[24].bit[0] = 0; | ||
1013 | state->Init_Ctrl[24].val[0] = 1; | ||
1014 | |||
1015 | state->Init_Ctrl[25].Ctrl_Num = RFSYN_R_DIV ; | ||
1016 | state->Init_Ctrl[25].size = 2 ; | ||
1017 | state->Init_Ctrl[25].addr[0] = 22; | ||
1018 | state->Init_Ctrl[25].bit[0] = 0; | ||
1019 | state->Init_Ctrl[25].val[0] = 1; | ||
1020 | state->Init_Ctrl[25].addr[1] = 22; | ||
1021 | state->Init_Ctrl[25].bit[1] = 1; | ||
1022 | state->Init_Ctrl[25].val[1] = 1; | ||
1023 | |||
1024 | state->Init_Ctrl[26].Ctrl_Num = SEQ_EXTSYNTHCALIF ; | ||
1025 | state->Init_Ctrl[26].size = 1 ; | ||
1026 | state->Init_Ctrl[26].addr[0] = 134; | ||
1027 | state->Init_Ctrl[26].bit[0] = 2; | ||
1028 | state->Init_Ctrl[26].val[0] = 0; | ||
1029 | |||
1030 | state->Init_Ctrl[27].Ctrl_Num = SEQ_EXTDCCAL ; | ||
1031 | state->Init_Ctrl[27].size = 1 ; | ||
1032 | state->Init_Ctrl[27].addr[0] = 137; | ||
1033 | state->Init_Ctrl[27].bit[0] = 3; | ||
1034 | state->Init_Ctrl[27].val[0] = 0; | ||
1035 | |||
1036 | state->Init_Ctrl[28].Ctrl_Num = AGC_EN_RSSI ; | ||
1037 | state->Init_Ctrl[28].size = 1 ; | ||
1038 | state->Init_Ctrl[28].addr[0] = 77; | ||
1039 | state->Init_Ctrl[28].bit[0] = 7; | ||
1040 | state->Init_Ctrl[28].val[0] = 0; | ||
1041 | |||
1042 | state->Init_Ctrl[29].Ctrl_Num = RFA_ENCLKRFAGC ; | ||
1043 | state->Init_Ctrl[29].size = 1 ; | ||
1044 | state->Init_Ctrl[29].addr[0] = 166; | ||
1045 | state->Init_Ctrl[29].bit[0] = 7; | ||
1046 | state->Init_Ctrl[29].val[0] = 1; | ||
1047 | |||
1048 | state->Init_Ctrl[30].Ctrl_Num = RFA_RSSI_REFH ; | ||
1049 | state->Init_Ctrl[30].size = 3 ; | ||
1050 | state->Init_Ctrl[30].addr[0] = 166; | ||
1051 | state->Init_Ctrl[30].bit[0] = 0; | ||
1052 | state->Init_Ctrl[30].val[0] = 0; | ||
1053 | state->Init_Ctrl[30].addr[1] = 166; | ||
1054 | state->Init_Ctrl[30].bit[1] = 1; | ||
1055 | state->Init_Ctrl[30].val[1] = 1; | ||
1056 | state->Init_Ctrl[30].addr[2] = 166; | ||
1057 | state->Init_Ctrl[30].bit[2] = 2; | ||
1058 | state->Init_Ctrl[30].val[2] = 1; | ||
1059 | |||
1060 | state->Init_Ctrl[31].Ctrl_Num = RFA_RSSI_REF ; | ||
1061 | state->Init_Ctrl[31].size = 3 ; | ||
1062 | state->Init_Ctrl[31].addr[0] = 166; | ||
1063 | state->Init_Ctrl[31].bit[0] = 3; | ||
1064 | state->Init_Ctrl[31].val[0] = 1; | ||
1065 | state->Init_Ctrl[31].addr[1] = 166; | ||
1066 | state->Init_Ctrl[31].bit[1] = 4; | ||
1067 | state->Init_Ctrl[31].val[1] = 0; | ||
1068 | state->Init_Ctrl[31].addr[2] = 166; | ||
1069 | state->Init_Ctrl[31].bit[2] = 5; | ||
1070 | state->Init_Ctrl[31].val[2] = 1; | ||
1071 | |||
1072 | state->Init_Ctrl[32].Ctrl_Num = RFA_RSSI_REFL ; | ||
1073 | state->Init_Ctrl[32].size = 3 ; | ||
1074 | state->Init_Ctrl[32].addr[0] = 167; | ||
1075 | state->Init_Ctrl[32].bit[0] = 0; | ||
1076 | state->Init_Ctrl[32].val[0] = 1; | ||
1077 | state->Init_Ctrl[32].addr[1] = 167; | ||
1078 | state->Init_Ctrl[32].bit[1] = 1; | ||
1079 | state->Init_Ctrl[32].val[1] = 1; | ||
1080 | state->Init_Ctrl[32].addr[2] = 167; | ||
1081 | state->Init_Ctrl[32].bit[2] = 2; | ||
1082 | state->Init_Ctrl[32].val[2] = 0; | ||
1083 | |||
1084 | state->Init_Ctrl[33].Ctrl_Num = RFA_FLR ; | ||
1085 | state->Init_Ctrl[33].size = 4 ; | ||
1086 | state->Init_Ctrl[33].addr[0] = 168; | ||
1087 | state->Init_Ctrl[33].bit[0] = 0; | ||
1088 | state->Init_Ctrl[33].val[0] = 0; | ||
1089 | state->Init_Ctrl[33].addr[1] = 168; | ||
1090 | state->Init_Ctrl[33].bit[1] = 1; | ||
1091 | state->Init_Ctrl[33].val[1] = 1; | ||
1092 | state->Init_Ctrl[33].addr[2] = 168; | ||
1093 | state->Init_Ctrl[33].bit[2] = 2; | ||
1094 | state->Init_Ctrl[33].val[2] = 0; | ||
1095 | state->Init_Ctrl[33].addr[3] = 168; | ||
1096 | state->Init_Ctrl[33].bit[3] = 3; | ||
1097 | state->Init_Ctrl[33].val[3] = 0; | ||
1098 | |||
1099 | state->Init_Ctrl[34].Ctrl_Num = RFA_CEIL ; | ||
1100 | state->Init_Ctrl[34].size = 4 ; | ||
1101 | state->Init_Ctrl[34].addr[0] = 168; | ||
1102 | state->Init_Ctrl[34].bit[0] = 4; | ||
1103 | state->Init_Ctrl[34].val[0] = 1; | ||
1104 | state->Init_Ctrl[34].addr[1] = 168; | ||
1105 | state->Init_Ctrl[34].bit[1] = 5; | ||
1106 | state->Init_Ctrl[34].val[1] = 1; | ||
1107 | state->Init_Ctrl[34].addr[2] = 168; | ||
1108 | state->Init_Ctrl[34].bit[2] = 6; | ||
1109 | state->Init_Ctrl[34].val[2] = 1; | ||
1110 | state->Init_Ctrl[34].addr[3] = 168; | ||
1111 | state->Init_Ctrl[34].bit[3] = 7; | ||
1112 | state->Init_Ctrl[34].val[3] = 1; | ||
1113 | |||
1114 | state->Init_Ctrl[35].Ctrl_Num = SEQ_EXTIQFSMPULSE ; | ||
1115 | state->Init_Ctrl[35].size = 1 ; | ||
1116 | state->Init_Ctrl[35].addr[0] = 135; | ||
1117 | state->Init_Ctrl[35].bit[0] = 0; | ||
1118 | state->Init_Ctrl[35].val[0] = 0; | ||
1119 | |||
1120 | state->Init_Ctrl[36].Ctrl_Num = OVERRIDE_1 ; | ||
1121 | state->Init_Ctrl[36].size = 1 ; | ||
1122 | state->Init_Ctrl[36].addr[0] = 56; | ||
1123 | state->Init_Ctrl[36].bit[0] = 3; | ||
1124 | state->Init_Ctrl[36].val[0] = 0; | ||
1125 | |||
1126 | state->Init_Ctrl[37].Ctrl_Num = BB_INITSTATE_DLPF_TUNE ; | ||
1127 | state->Init_Ctrl[37].size = 7 ; | ||
1128 | state->Init_Ctrl[37].addr[0] = 59; | ||
1129 | state->Init_Ctrl[37].bit[0] = 1; | ||
1130 | state->Init_Ctrl[37].val[0] = 0; | ||
1131 | state->Init_Ctrl[37].addr[1] = 59; | ||
1132 | state->Init_Ctrl[37].bit[1] = 2; | ||
1133 | state->Init_Ctrl[37].val[1] = 0; | ||
1134 | state->Init_Ctrl[37].addr[2] = 59; | ||
1135 | state->Init_Ctrl[37].bit[2] = 3; | ||
1136 | state->Init_Ctrl[37].val[2] = 0; | ||
1137 | state->Init_Ctrl[37].addr[3] = 59; | ||
1138 | state->Init_Ctrl[37].bit[3] = 4; | ||
1139 | state->Init_Ctrl[37].val[3] = 0; | ||
1140 | state->Init_Ctrl[37].addr[4] = 59; | ||
1141 | state->Init_Ctrl[37].bit[4] = 5; | ||
1142 | state->Init_Ctrl[37].val[4] = 0; | ||
1143 | state->Init_Ctrl[37].addr[5] = 59; | ||
1144 | state->Init_Ctrl[37].bit[5] = 6; | ||
1145 | state->Init_Ctrl[37].val[5] = 0; | ||
1146 | state->Init_Ctrl[37].addr[6] = 59; | ||
1147 | state->Init_Ctrl[37].bit[6] = 7; | ||
1148 | state->Init_Ctrl[37].val[6] = 0; | ||
1149 | |||
1150 | state->Init_Ctrl[38].Ctrl_Num = TG_R_DIV ; | ||
1151 | state->Init_Ctrl[38].size = 6 ; | ||
1152 | state->Init_Ctrl[38].addr[0] = 32; | ||
1153 | state->Init_Ctrl[38].bit[0] = 2; | ||
1154 | state->Init_Ctrl[38].val[0] = 0; | ||
1155 | state->Init_Ctrl[38].addr[1] = 32; | ||
1156 | state->Init_Ctrl[38].bit[1] = 3; | ||
1157 | state->Init_Ctrl[38].val[1] = 0; | ||
1158 | state->Init_Ctrl[38].addr[2] = 32; | ||
1159 | state->Init_Ctrl[38].bit[2] = 4; | ||
1160 | state->Init_Ctrl[38].val[2] = 0; | ||
1161 | state->Init_Ctrl[38].addr[3] = 32; | ||
1162 | state->Init_Ctrl[38].bit[3] = 5; | ||
1163 | state->Init_Ctrl[38].val[3] = 0; | ||
1164 | state->Init_Ctrl[38].addr[4] = 32; | ||
1165 | state->Init_Ctrl[38].bit[4] = 6; | ||
1166 | state->Init_Ctrl[38].val[4] = 1; | ||
1167 | state->Init_Ctrl[38].addr[5] = 32; | ||
1168 | state->Init_Ctrl[38].bit[5] = 7; | ||
1169 | state->Init_Ctrl[38].val[5] = 0; | ||
1170 | |||
1171 | state->Init_Ctrl[39].Ctrl_Num = EN_CHP_LIN_B ; | ||
1172 | state->Init_Ctrl[39].size = 1 ; | ||
1173 | state->Init_Ctrl[39].addr[0] = 25; | ||
1174 | state->Init_Ctrl[39].bit[0] = 3; | ||
1175 | state->Init_Ctrl[39].val[0] = 1; | ||
1176 | |||
1177 | |||
1178 | state->CH_Ctrl_Num = CHCTRL_NUM ; | ||
1179 | |||
1180 | state->CH_Ctrl[0].Ctrl_Num = DN_POLY ; | ||
1181 | state->CH_Ctrl[0].size = 2 ; | ||
1182 | state->CH_Ctrl[0].addr[0] = 68; | ||
1183 | state->CH_Ctrl[0].bit[0] = 6; | ||
1184 | state->CH_Ctrl[0].val[0] = 1; | ||
1185 | state->CH_Ctrl[0].addr[1] = 68; | ||
1186 | state->CH_Ctrl[0].bit[1] = 7; | ||
1187 | state->CH_Ctrl[0].val[1] = 1; | ||
1188 | |||
1189 | state->CH_Ctrl[1].Ctrl_Num = DN_RFGAIN ; | ||
1190 | state->CH_Ctrl[1].size = 2 ; | ||
1191 | state->CH_Ctrl[1].addr[0] = 70; | ||
1192 | state->CH_Ctrl[1].bit[0] = 6; | ||
1193 | state->CH_Ctrl[1].val[0] = 1; | ||
1194 | state->CH_Ctrl[1].addr[1] = 70; | ||
1195 | state->CH_Ctrl[1].bit[1] = 7; | ||
1196 | state->CH_Ctrl[1].val[1] = 0; | ||
1197 | |||
1198 | state->CH_Ctrl[2].Ctrl_Num = DN_CAP_RFLPF ; | ||
1199 | state->CH_Ctrl[2].size = 9 ; | ||
1200 | state->CH_Ctrl[2].addr[0] = 69; | ||
1201 | state->CH_Ctrl[2].bit[0] = 5; | ||
1202 | state->CH_Ctrl[2].val[0] = 0; | ||
1203 | state->CH_Ctrl[2].addr[1] = 69; | ||
1204 | state->CH_Ctrl[2].bit[1] = 6; | ||
1205 | state->CH_Ctrl[2].val[1] = 0; | ||
1206 | state->CH_Ctrl[2].addr[2] = 69; | ||
1207 | state->CH_Ctrl[2].bit[2] = 7; | ||
1208 | state->CH_Ctrl[2].val[2] = 0; | ||
1209 | state->CH_Ctrl[2].addr[3] = 68; | ||
1210 | state->CH_Ctrl[2].bit[3] = 0; | ||
1211 | state->CH_Ctrl[2].val[3] = 0; | ||
1212 | state->CH_Ctrl[2].addr[4] = 68; | ||
1213 | state->CH_Ctrl[2].bit[4] = 1; | ||
1214 | state->CH_Ctrl[2].val[4] = 0; | ||
1215 | state->CH_Ctrl[2].addr[5] = 68; | ||
1216 | state->CH_Ctrl[2].bit[5] = 2; | ||
1217 | state->CH_Ctrl[2].val[5] = 0; | ||
1218 | state->CH_Ctrl[2].addr[6] = 68; | ||
1219 | state->CH_Ctrl[2].bit[6] = 3; | ||
1220 | state->CH_Ctrl[2].val[6] = 0; | ||
1221 | state->CH_Ctrl[2].addr[7] = 68; | ||
1222 | state->CH_Ctrl[2].bit[7] = 4; | ||
1223 | state->CH_Ctrl[2].val[7] = 0; | ||
1224 | state->CH_Ctrl[2].addr[8] = 68; | ||
1225 | state->CH_Ctrl[2].bit[8] = 5; | ||
1226 | state->CH_Ctrl[2].val[8] = 0; | ||
1227 | |||
1228 | state->CH_Ctrl[3].Ctrl_Num = DN_EN_VHFUHFBAR ; | ||
1229 | state->CH_Ctrl[3].size = 1 ; | ||
1230 | state->CH_Ctrl[3].addr[0] = 70; | ||
1231 | state->CH_Ctrl[3].bit[0] = 5; | ||
1232 | state->CH_Ctrl[3].val[0] = 0; | ||
1233 | |||
1234 | state->CH_Ctrl[4].Ctrl_Num = DN_GAIN_ADJUST ; | ||
1235 | state->CH_Ctrl[4].size = 3 ; | ||
1236 | state->CH_Ctrl[4].addr[0] = 73; | ||
1237 | state->CH_Ctrl[4].bit[0] = 4; | ||
1238 | state->CH_Ctrl[4].val[0] = 0; | ||
1239 | state->CH_Ctrl[4].addr[1] = 73; | ||
1240 | state->CH_Ctrl[4].bit[1] = 5; | ||
1241 | state->CH_Ctrl[4].val[1] = 1; | ||
1242 | state->CH_Ctrl[4].addr[2] = 73; | ||
1243 | state->CH_Ctrl[4].bit[2] = 6; | ||
1244 | state->CH_Ctrl[4].val[2] = 0; | ||
1245 | |||
1246 | state->CH_Ctrl[5].Ctrl_Num = DN_IQTNBUF_AMP ; | ||
1247 | state->CH_Ctrl[5].size = 4 ; | ||
1248 | state->CH_Ctrl[5].addr[0] = 70; | ||
1249 | state->CH_Ctrl[5].bit[0] = 0; | ||
1250 | state->CH_Ctrl[5].val[0] = 0; | ||
1251 | state->CH_Ctrl[5].addr[1] = 70; | ||
1252 | state->CH_Ctrl[5].bit[1] = 1; | ||
1253 | state->CH_Ctrl[5].val[1] = 0; | ||
1254 | state->CH_Ctrl[5].addr[2] = 70; | ||
1255 | state->CH_Ctrl[5].bit[2] = 2; | ||
1256 | state->CH_Ctrl[5].val[2] = 0; | ||
1257 | state->CH_Ctrl[5].addr[3] = 70; | ||
1258 | state->CH_Ctrl[5].bit[3] = 3; | ||
1259 | state->CH_Ctrl[5].val[3] = 0; | ||
1260 | |||
1261 | state->CH_Ctrl[6].Ctrl_Num = DN_IQTNGNBFBIAS_BST ; | ||
1262 | state->CH_Ctrl[6].size = 1 ; | ||
1263 | state->CH_Ctrl[6].addr[0] = 70; | ||
1264 | state->CH_Ctrl[6].bit[0] = 4; | ||
1265 | state->CH_Ctrl[6].val[0] = 1; | ||
1266 | |||
1267 | state->CH_Ctrl[7].Ctrl_Num = RFSYN_EN_OUTMUX ; | ||
1268 | state->CH_Ctrl[7].size = 1 ; | ||
1269 | state->CH_Ctrl[7].addr[0] = 111; | ||
1270 | state->CH_Ctrl[7].bit[0] = 4; | ||
1271 | state->CH_Ctrl[7].val[0] = 0; | ||
1272 | |||
1273 | state->CH_Ctrl[8].Ctrl_Num = RFSYN_SEL_VCO_OUT ; | ||
1274 | state->CH_Ctrl[8].size = 1 ; | ||
1275 | state->CH_Ctrl[8].addr[0] = 111; | ||
1276 | state->CH_Ctrl[8].bit[0] = 7; | ||
1277 | state->CH_Ctrl[8].val[0] = 1; | ||
1278 | |||
1279 | state->CH_Ctrl[9].Ctrl_Num = RFSYN_SEL_VCO_HI ; | ||
1280 | state->CH_Ctrl[9].size = 1 ; | ||
1281 | state->CH_Ctrl[9].addr[0] = 111; | ||
1282 | state->CH_Ctrl[9].bit[0] = 6; | ||
1283 | state->CH_Ctrl[9].val[0] = 1; | ||
1284 | |||
1285 | state->CH_Ctrl[10].Ctrl_Num = RFSYN_SEL_DIVM ; | ||
1286 | state->CH_Ctrl[10].size = 1 ; | ||
1287 | state->CH_Ctrl[10].addr[0] = 111; | ||
1288 | state->CH_Ctrl[10].bit[0] = 5; | ||
1289 | state->CH_Ctrl[10].val[0] = 0; | ||
1290 | |||
1291 | state->CH_Ctrl[11].Ctrl_Num = RFSYN_RF_DIV_BIAS ; | ||
1292 | state->CH_Ctrl[11].size = 2 ; | ||
1293 | state->CH_Ctrl[11].addr[0] = 110; | ||
1294 | state->CH_Ctrl[11].bit[0] = 0; | ||
1295 | state->CH_Ctrl[11].val[0] = 1; | ||
1296 | state->CH_Ctrl[11].addr[1] = 110; | ||
1297 | state->CH_Ctrl[11].bit[1] = 1; | ||
1298 | state->CH_Ctrl[11].val[1] = 0; | ||
1299 | |||
1300 | state->CH_Ctrl[12].Ctrl_Num = DN_SEL_FREQ ; | ||
1301 | state->CH_Ctrl[12].size = 3 ; | ||
1302 | state->CH_Ctrl[12].addr[0] = 69; | ||
1303 | state->CH_Ctrl[12].bit[0] = 2; | ||
1304 | state->CH_Ctrl[12].val[0] = 0; | ||
1305 | state->CH_Ctrl[12].addr[1] = 69; | ||
1306 | state->CH_Ctrl[12].bit[1] = 3; | ||
1307 | state->CH_Ctrl[12].val[1] = 0; | ||
1308 | state->CH_Ctrl[12].addr[2] = 69; | ||
1309 | state->CH_Ctrl[12].bit[2] = 4; | ||
1310 | state->CH_Ctrl[12].val[2] = 0; | ||
1311 | |||
1312 | state->CH_Ctrl[13].Ctrl_Num = RFSYN_VCO_BIAS ; | ||
1313 | state->CH_Ctrl[13].size = 6 ; | ||
1314 | state->CH_Ctrl[13].addr[0] = 110; | ||
1315 | state->CH_Ctrl[13].bit[0] = 2; | ||
1316 | state->CH_Ctrl[13].val[0] = 0; | ||
1317 | state->CH_Ctrl[13].addr[1] = 110; | ||
1318 | state->CH_Ctrl[13].bit[1] = 3; | ||
1319 | state->CH_Ctrl[13].val[1] = 0; | ||
1320 | state->CH_Ctrl[13].addr[2] = 110; | ||
1321 | state->CH_Ctrl[13].bit[2] = 4; | ||
1322 | state->CH_Ctrl[13].val[2] = 0; | ||
1323 | state->CH_Ctrl[13].addr[3] = 110; | ||
1324 | state->CH_Ctrl[13].bit[3] = 5; | ||
1325 | state->CH_Ctrl[13].val[3] = 0; | ||
1326 | state->CH_Ctrl[13].addr[4] = 110; | ||
1327 | state->CH_Ctrl[13].bit[4] = 6; | ||
1328 | state->CH_Ctrl[13].val[4] = 0; | ||
1329 | state->CH_Ctrl[13].addr[5] = 110; | ||
1330 | state->CH_Ctrl[13].bit[5] = 7; | ||
1331 | state->CH_Ctrl[13].val[5] = 1; | ||
1332 | |||
1333 | state->CH_Ctrl[14].Ctrl_Num = CHCAL_INT_MOD_RF ; | ||
1334 | state->CH_Ctrl[14].size = 7 ; | ||
1335 | state->CH_Ctrl[14].addr[0] = 14; | ||
1336 | state->CH_Ctrl[14].bit[0] = 0; | ||
1337 | state->CH_Ctrl[14].val[0] = 0; | ||
1338 | state->CH_Ctrl[14].addr[1] = 14; | ||
1339 | state->CH_Ctrl[14].bit[1] = 1; | ||
1340 | state->CH_Ctrl[14].val[1] = 0; | ||
1341 | state->CH_Ctrl[14].addr[2] = 14; | ||
1342 | state->CH_Ctrl[14].bit[2] = 2; | ||
1343 | state->CH_Ctrl[14].val[2] = 0; | ||
1344 | state->CH_Ctrl[14].addr[3] = 14; | ||
1345 | state->CH_Ctrl[14].bit[3] = 3; | ||
1346 | state->CH_Ctrl[14].val[3] = 0; | ||
1347 | state->CH_Ctrl[14].addr[4] = 14; | ||
1348 | state->CH_Ctrl[14].bit[4] = 4; | ||
1349 | state->CH_Ctrl[14].val[4] = 0; | ||
1350 | state->CH_Ctrl[14].addr[5] = 14; | ||
1351 | state->CH_Ctrl[14].bit[5] = 5; | ||
1352 | state->CH_Ctrl[14].val[5] = 0; | ||
1353 | state->CH_Ctrl[14].addr[6] = 14; | ||
1354 | state->CH_Ctrl[14].bit[6] = 6; | ||
1355 | state->CH_Ctrl[14].val[6] = 0; | ||
1356 | |||
1357 | state->CH_Ctrl[15].Ctrl_Num = CHCAL_FRAC_MOD_RF ; | ||
1358 | state->CH_Ctrl[15].size = 18 ; | ||
1359 | state->CH_Ctrl[15].addr[0] = 17; | ||
1360 | state->CH_Ctrl[15].bit[0] = 6; | ||
1361 | state->CH_Ctrl[15].val[0] = 0; | ||
1362 | state->CH_Ctrl[15].addr[1] = 17; | ||
1363 | state->CH_Ctrl[15].bit[1] = 7; | ||
1364 | state->CH_Ctrl[15].val[1] = 0; | ||
1365 | state->CH_Ctrl[15].addr[2] = 16; | ||
1366 | state->CH_Ctrl[15].bit[2] = 0; | ||
1367 | state->CH_Ctrl[15].val[2] = 0; | ||
1368 | state->CH_Ctrl[15].addr[3] = 16; | ||
1369 | state->CH_Ctrl[15].bit[3] = 1; | ||
1370 | state->CH_Ctrl[15].val[3] = 0; | ||
1371 | state->CH_Ctrl[15].addr[4] = 16; | ||
1372 | state->CH_Ctrl[15].bit[4] = 2; | ||
1373 | state->CH_Ctrl[15].val[4] = 0; | ||
1374 | state->CH_Ctrl[15].addr[5] = 16; | ||
1375 | state->CH_Ctrl[15].bit[5] = 3; | ||
1376 | state->CH_Ctrl[15].val[5] = 0; | ||
1377 | state->CH_Ctrl[15].addr[6] = 16; | ||
1378 | state->CH_Ctrl[15].bit[6] = 4; | ||
1379 | state->CH_Ctrl[15].val[6] = 0; | ||
1380 | state->CH_Ctrl[15].addr[7] = 16; | ||
1381 | state->CH_Ctrl[15].bit[7] = 5; | ||
1382 | state->CH_Ctrl[15].val[7] = 0; | ||
1383 | state->CH_Ctrl[15].addr[8] = 16; | ||
1384 | state->CH_Ctrl[15].bit[8] = 6; | ||
1385 | state->CH_Ctrl[15].val[8] = 0; | ||
1386 | state->CH_Ctrl[15].addr[9] = 16; | ||
1387 | state->CH_Ctrl[15].bit[9] = 7; | ||
1388 | state->CH_Ctrl[15].val[9] = 0; | ||
1389 | state->CH_Ctrl[15].addr[10] = 15; | ||
1390 | state->CH_Ctrl[15].bit[10] = 0; | ||
1391 | state->CH_Ctrl[15].val[10] = 0; | ||
1392 | state->CH_Ctrl[15].addr[11] = 15; | ||
1393 | state->CH_Ctrl[15].bit[11] = 1; | ||
1394 | state->CH_Ctrl[15].val[11] = 0; | ||
1395 | state->CH_Ctrl[15].addr[12] = 15; | ||
1396 | state->CH_Ctrl[15].bit[12] = 2; | ||
1397 | state->CH_Ctrl[15].val[12] = 0; | ||
1398 | state->CH_Ctrl[15].addr[13] = 15; | ||
1399 | state->CH_Ctrl[15].bit[13] = 3; | ||
1400 | state->CH_Ctrl[15].val[13] = 0; | ||
1401 | state->CH_Ctrl[15].addr[14] = 15; | ||
1402 | state->CH_Ctrl[15].bit[14] = 4; | ||
1403 | state->CH_Ctrl[15].val[14] = 0; | ||
1404 | state->CH_Ctrl[15].addr[15] = 15; | ||
1405 | state->CH_Ctrl[15].bit[15] = 5; | ||
1406 | state->CH_Ctrl[15].val[15] = 0; | ||
1407 | state->CH_Ctrl[15].addr[16] = 15; | ||
1408 | state->CH_Ctrl[15].bit[16] = 6; | ||
1409 | state->CH_Ctrl[15].val[16] = 1; | ||
1410 | state->CH_Ctrl[15].addr[17] = 15; | ||
1411 | state->CH_Ctrl[15].bit[17] = 7; | ||
1412 | state->CH_Ctrl[15].val[17] = 1; | ||
1413 | |||
1414 | state->CH_Ctrl[16].Ctrl_Num = RFSYN_LPF_R ; | ||
1415 | state->CH_Ctrl[16].size = 5 ; | ||
1416 | state->CH_Ctrl[16].addr[0] = 112; | ||
1417 | state->CH_Ctrl[16].bit[0] = 0; | ||
1418 | state->CH_Ctrl[16].val[0] = 0; | ||
1419 | state->CH_Ctrl[16].addr[1] = 112; | ||
1420 | state->CH_Ctrl[16].bit[1] = 1; | ||
1421 | state->CH_Ctrl[16].val[1] = 0; | ||
1422 | state->CH_Ctrl[16].addr[2] = 112; | ||
1423 | state->CH_Ctrl[16].bit[2] = 2; | ||
1424 | state->CH_Ctrl[16].val[2] = 0; | ||
1425 | state->CH_Ctrl[16].addr[3] = 112; | ||
1426 | state->CH_Ctrl[16].bit[3] = 3; | ||
1427 | state->CH_Ctrl[16].val[3] = 0; | ||
1428 | state->CH_Ctrl[16].addr[4] = 112; | ||
1429 | state->CH_Ctrl[16].bit[4] = 4; | ||
1430 | state->CH_Ctrl[16].val[4] = 1; | ||
1431 | |||
1432 | state->CH_Ctrl[17].Ctrl_Num = CHCAL_EN_INT_RF ; | ||
1433 | state->CH_Ctrl[17].size = 1 ; | ||
1434 | state->CH_Ctrl[17].addr[0] = 14; | ||
1435 | state->CH_Ctrl[17].bit[0] = 7; | ||
1436 | state->CH_Ctrl[17].val[0] = 0; | ||
1437 | |||
1438 | state->CH_Ctrl[18].Ctrl_Num = TG_LO_DIVVAL ; | ||
1439 | state->CH_Ctrl[18].size = 4 ; | ||
1440 | state->CH_Ctrl[18].addr[0] = 107; | ||
1441 | state->CH_Ctrl[18].bit[0] = 3; | ||
1442 | state->CH_Ctrl[18].val[0] = 0; | ||
1443 | state->CH_Ctrl[18].addr[1] = 107; | ||
1444 | state->CH_Ctrl[18].bit[1] = 4; | ||
1445 | state->CH_Ctrl[18].val[1] = 0; | ||
1446 | state->CH_Ctrl[18].addr[2] = 107; | ||
1447 | state->CH_Ctrl[18].bit[2] = 5; | ||
1448 | state->CH_Ctrl[18].val[2] = 0; | ||
1449 | state->CH_Ctrl[18].addr[3] = 107; | ||
1450 | state->CH_Ctrl[18].bit[3] = 6; | ||
1451 | state->CH_Ctrl[18].val[3] = 0; | ||
1452 | |||
1453 | state->CH_Ctrl[19].Ctrl_Num = TG_LO_SELVAL ; | ||
1454 | state->CH_Ctrl[19].size = 3 ; | ||
1455 | state->CH_Ctrl[19].addr[0] = 107; | ||
1456 | state->CH_Ctrl[19].bit[0] = 7; | ||
1457 | state->CH_Ctrl[19].val[0] = 1; | ||
1458 | state->CH_Ctrl[19].addr[1] = 106; | ||
1459 | state->CH_Ctrl[19].bit[1] = 0; | ||
1460 | state->CH_Ctrl[19].val[1] = 1; | ||
1461 | state->CH_Ctrl[19].addr[2] = 106; | ||
1462 | state->CH_Ctrl[19].bit[2] = 1; | ||
1463 | state->CH_Ctrl[19].val[2] = 1; | ||
1464 | |||
1465 | state->CH_Ctrl[20].Ctrl_Num = TG_DIV_VAL ; | ||
1466 | state->CH_Ctrl[20].size = 11 ; | ||
1467 | state->CH_Ctrl[20].addr[0] = 109; | ||
1468 | state->CH_Ctrl[20].bit[0] = 2; | ||
1469 | state->CH_Ctrl[20].val[0] = 0; | ||
1470 | state->CH_Ctrl[20].addr[1] = 109; | ||
1471 | state->CH_Ctrl[20].bit[1] = 3; | ||
1472 | state->CH_Ctrl[20].val[1] = 0; | ||
1473 | state->CH_Ctrl[20].addr[2] = 109; | ||
1474 | state->CH_Ctrl[20].bit[2] = 4; | ||
1475 | state->CH_Ctrl[20].val[2] = 0; | ||
1476 | state->CH_Ctrl[20].addr[3] = 109; | ||
1477 | state->CH_Ctrl[20].bit[3] = 5; | ||
1478 | state->CH_Ctrl[20].val[3] = 0; | ||
1479 | state->CH_Ctrl[20].addr[4] = 109; | ||
1480 | state->CH_Ctrl[20].bit[4] = 6; | ||
1481 | state->CH_Ctrl[20].val[4] = 0; | ||
1482 | state->CH_Ctrl[20].addr[5] = 109; | ||
1483 | state->CH_Ctrl[20].bit[5] = 7; | ||
1484 | state->CH_Ctrl[20].val[5] = 0; | ||
1485 | state->CH_Ctrl[20].addr[6] = 108; | ||
1486 | state->CH_Ctrl[20].bit[6] = 0; | ||
1487 | state->CH_Ctrl[20].val[6] = 0; | ||
1488 | state->CH_Ctrl[20].addr[7] = 108; | ||
1489 | state->CH_Ctrl[20].bit[7] = 1; | ||
1490 | state->CH_Ctrl[20].val[7] = 0; | ||
1491 | state->CH_Ctrl[20].addr[8] = 108; | ||
1492 | state->CH_Ctrl[20].bit[8] = 2; | ||
1493 | state->CH_Ctrl[20].val[8] = 1; | ||
1494 | state->CH_Ctrl[20].addr[9] = 108; | ||
1495 | state->CH_Ctrl[20].bit[9] = 3; | ||
1496 | state->CH_Ctrl[20].val[9] = 1; | ||
1497 | state->CH_Ctrl[20].addr[10] = 108; | ||
1498 | state->CH_Ctrl[20].bit[10] = 4; | ||
1499 | state->CH_Ctrl[20].val[10] = 1; | ||
1500 | |||
1501 | state->CH_Ctrl[21].Ctrl_Num = TG_VCO_BIAS ; | ||
1502 | state->CH_Ctrl[21].size = 6 ; | ||
1503 | state->CH_Ctrl[21].addr[0] = 106; | ||
1504 | state->CH_Ctrl[21].bit[0] = 2; | ||
1505 | state->CH_Ctrl[21].val[0] = 0; | ||
1506 | state->CH_Ctrl[21].addr[1] = 106; | ||
1507 | state->CH_Ctrl[21].bit[1] = 3; | ||
1508 | state->CH_Ctrl[21].val[1] = 0; | ||
1509 | state->CH_Ctrl[21].addr[2] = 106; | ||
1510 | state->CH_Ctrl[21].bit[2] = 4; | ||
1511 | state->CH_Ctrl[21].val[2] = 0; | ||
1512 | state->CH_Ctrl[21].addr[3] = 106; | ||
1513 | state->CH_Ctrl[21].bit[3] = 5; | ||
1514 | state->CH_Ctrl[21].val[3] = 0; | ||
1515 | state->CH_Ctrl[21].addr[4] = 106; | ||
1516 | state->CH_Ctrl[21].bit[4] = 6; | ||
1517 | state->CH_Ctrl[21].val[4] = 0; | ||
1518 | state->CH_Ctrl[21].addr[5] = 106; | ||
1519 | state->CH_Ctrl[21].bit[5] = 7; | ||
1520 | state->CH_Ctrl[21].val[5] = 1; | ||
1521 | |||
1522 | state->CH_Ctrl[22].Ctrl_Num = SEQ_EXTPOWERUP ; | ||
1523 | state->CH_Ctrl[22].size = 1 ; | ||
1524 | state->CH_Ctrl[22].addr[0] = 138; | ||
1525 | state->CH_Ctrl[22].bit[0] = 4; | ||
1526 | state->CH_Ctrl[22].val[0] = 1; | ||
1527 | |||
1528 | state->CH_Ctrl[23].Ctrl_Num = OVERRIDE_2 ; | ||
1529 | state->CH_Ctrl[23].size = 1 ; | ||
1530 | state->CH_Ctrl[23].addr[0] = 17; | ||
1531 | state->CH_Ctrl[23].bit[0] = 5; | ||
1532 | state->CH_Ctrl[23].val[0] = 0; | ||
1533 | |||
1534 | state->CH_Ctrl[24].Ctrl_Num = OVERRIDE_3 ; | ||
1535 | state->CH_Ctrl[24].size = 1 ; | ||
1536 | state->CH_Ctrl[24].addr[0] = 111; | ||
1537 | state->CH_Ctrl[24].bit[0] = 3; | ||
1538 | state->CH_Ctrl[24].val[0] = 0; | ||
1539 | |||
1540 | state->CH_Ctrl[25].Ctrl_Num = OVERRIDE_4 ; | ||
1541 | state->CH_Ctrl[25].size = 1 ; | ||
1542 | state->CH_Ctrl[25].addr[0] = 112; | ||
1543 | state->CH_Ctrl[25].bit[0] = 7; | ||
1544 | state->CH_Ctrl[25].val[0] = 0; | ||
1545 | |||
1546 | state->CH_Ctrl[26].Ctrl_Num = SEQ_FSM_PULSE ; | ||
1547 | state->CH_Ctrl[26].size = 1 ; | ||
1548 | state->CH_Ctrl[26].addr[0] = 136; | ||
1549 | state->CH_Ctrl[26].bit[0] = 7; | ||
1550 | state->CH_Ctrl[26].val[0] = 0; | ||
1551 | |||
1552 | state->CH_Ctrl[27].Ctrl_Num = GPIO_4B ; | ||
1553 | state->CH_Ctrl[27].size = 1 ; | ||
1554 | state->CH_Ctrl[27].addr[0] = 149; | ||
1555 | state->CH_Ctrl[27].bit[0] = 7; | ||
1556 | state->CH_Ctrl[27].val[0] = 0; | ||
1557 | |||
1558 | state->CH_Ctrl[28].Ctrl_Num = GPIO_3B ; | ||
1559 | state->CH_Ctrl[28].size = 1 ; | ||
1560 | state->CH_Ctrl[28].addr[0] = 149; | ||
1561 | state->CH_Ctrl[28].bit[0] = 6; | ||
1562 | state->CH_Ctrl[28].val[0] = 0; | ||
1563 | |||
1564 | state->CH_Ctrl[29].Ctrl_Num = GPIO_4 ; | ||
1565 | state->CH_Ctrl[29].size = 1 ; | ||
1566 | state->CH_Ctrl[29].addr[0] = 149; | ||
1567 | state->CH_Ctrl[29].bit[0] = 5; | ||
1568 | state->CH_Ctrl[29].val[0] = 1; | ||
1569 | |||
1570 | state->CH_Ctrl[30].Ctrl_Num = GPIO_3 ; | ||
1571 | state->CH_Ctrl[30].size = 1 ; | ||
1572 | state->CH_Ctrl[30].addr[0] = 149; | ||
1573 | state->CH_Ctrl[30].bit[0] = 4; | ||
1574 | state->CH_Ctrl[30].val[0] = 1; | ||
1575 | |||
1576 | state->CH_Ctrl[31].Ctrl_Num = GPIO_1B ; | ||
1577 | state->CH_Ctrl[31].size = 1 ; | ||
1578 | state->CH_Ctrl[31].addr[0] = 149; | ||
1579 | state->CH_Ctrl[31].bit[0] = 3; | ||
1580 | state->CH_Ctrl[31].val[0] = 0; | ||
1581 | |||
1582 | state->CH_Ctrl[32].Ctrl_Num = DAC_A_ENABLE ; | ||
1583 | state->CH_Ctrl[32].size = 1 ; | ||
1584 | state->CH_Ctrl[32].addr[0] = 93; | ||
1585 | state->CH_Ctrl[32].bit[0] = 1; | ||
1586 | state->CH_Ctrl[32].val[0] = 0; | ||
1587 | |||
1588 | state->CH_Ctrl[33].Ctrl_Num = DAC_B_ENABLE ; | ||
1589 | state->CH_Ctrl[33].size = 1 ; | ||
1590 | state->CH_Ctrl[33].addr[0] = 93; | ||
1591 | state->CH_Ctrl[33].bit[0] = 0; | ||
1592 | state->CH_Ctrl[33].val[0] = 0; | ||
1593 | |||
1594 | state->CH_Ctrl[34].Ctrl_Num = DAC_DIN_A ; | ||
1595 | state->CH_Ctrl[34].size = 6 ; | ||
1596 | state->CH_Ctrl[34].addr[0] = 92; | ||
1597 | state->CH_Ctrl[34].bit[0] = 2; | ||
1598 | state->CH_Ctrl[34].val[0] = 0; | ||
1599 | state->CH_Ctrl[34].addr[1] = 92; | ||
1600 | state->CH_Ctrl[34].bit[1] = 3; | ||
1601 | state->CH_Ctrl[34].val[1] = 0; | ||
1602 | state->CH_Ctrl[34].addr[2] = 92; | ||
1603 | state->CH_Ctrl[34].bit[2] = 4; | ||
1604 | state->CH_Ctrl[34].val[2] = 0; | ||
1605 | state->CH_Ctrl[34].addr[3] = 92; | ||
1606 | state->CH_Ctrl[34].bit[3] = 5; | ||
1607 | state->CH_Ctrl[34].val[3] = 0; | ||
1608 | state->CH_Ctrl[34].addr[4] = 92; | ||
1609 | state->CH_Ctrl[34].bit[4] = 6; | ||
1610 | state->CH_Ctrl[34].val[4] = 0; | ||
1611 | state->CH_Ctrl[34].addr[5] = 92; | ||
1612 | state->CH_Ctrl[34].bit[5] = 7; | ||
1613 | state->CH_Ctrl[34].val[5] = 0; | ||
1614 | |||
1615 | state->CH_Ctrl[35].Ctrl_Num = DAC_DIN_B ; | ||
1616 | state->CH_Ctrl[35].size = 6 ; | ||
1617 | state->CH_Ctrl[35].addr[0] = 93; | ||
1618 | state->CH_Ctrl[35].bit[0] = 2; | ||
1619 | state->CH_Ctrl[35].val[0] = 0; | ||
1620 | state->CH_Ctrl[35].addr[1] = 93; | ||
1621 | state->CH_Ctrl[35].bit[1] = 3; | ||
1622 | state->CH_Ctrl[35].val[1] = 0; | ||
1623 | state->CH_Ctrl[35].addr[2] = 93; | ||
1624 | state->CH_Ctrl[35].bit[2] = 4; | ||
1625 | state->CH_Ctrl[35].val[2] = 0; | ||
1626 | state->CH_Ctrl[35].addr[3] = 93; | ||
1627 | state->CH_Ctrl[35].bit[3] = 5; | ||
1628 | state->CH_Ctrl[35].val[3] = 0; | ||
1629 | state->CH_Ctrl[35].addr[4] = 93; | ||
1630 | state->CH_Ctrl[35].bit[4] = 6; | ||
1631 | state->CH_Ctrl[35].val[4] = 0; | ||
1632 | state->CH_Ctrl[35].addr[5] = 93; | ||
1633 | state->CH_Ctrl[35].bit[5] = 7; | ||
1634 | state->CH_Ctrl[35].val[5] = 0; | ||
1635 | |||
1636 | #ifdef _MXL_PRODUCTION | ||
1637 | state->CH_Ctrl[36].Ctrl_Num = RFSYN_EN_DIV ; | ||
1638 | state->CH_Ctrl[36].size = 1 ; | ||
1639 | state->CH_Ctrl[36].addr[0] = 109; | ||
1640 | state->CH_Ctrl[36].bit[0] = 1; | ||
1641 | state->CH_Ctrl[36].val[0] = 1; | ||
1642 | |||
1643 | state->CH_Ctrl[37].Ctrl_Num = RFSYN_DIVM ; | ||
1644 | state->CH_Ctrl[37].size = 2 ; | ||
1645 | state->CH_Ctrl[37].addr[0] = 112; | ||
1646 | state->CH_Ctrl[37].bit[0] = 5; | ||
1647 | state->CH_Ctrl[37].val[0] = 0; | ||
1648 | state->CH_Ctrl[37].addr[1] = 112; | ||
1649 | state->CH_Ctrl[37].bit[1] = 6; | ||
1650 | state->CH_Ctrl[37].val[1] = 0; | ||
1651 | |||
1652 | state->CH_Ctrl[38].Ctrl_Num = DN_BYPASS_AGC_I2C ; | ||
1653 | state->CH_Ctrl[38].size = 1 ; | ||
1654 | state->CH_Ctrl[38].addr[0] = 65; | ||
1655 | state->CH_Ctrl[38].bit[0] = 1; | ||
1656 | state->CH_Ctrl[38].val[0] = 0; | ||
1657 | #endif | ||
1658 | |||
1659 | return 0 ; | ||
1660 | } | ||
1661 | |||
1662 | static void InitTunerControls(struct dvb_frontend *fe) | ||
1663 | { | ||
1664 | MXL5005_RegisterInit(fe); | ||
1665 | MXL5005_ControlInit(fe); | ||
1666 | #ifdef _MXL_INTERNAL | ||
1667 | MXL5005_MXLControlInit(fe); | ||
1668 | #endif | ||
1669 | } | ||
1670 | |||
1671 | static u16 MXL5005_TunerConfig(struct dvb_frontend *fe, | ||
1672 | u8 Mode, /* 0: Analog Mode ; 1: Digital Mode */ | ||
1673 | u8 IF_mode, /* for Analog Mode, 0: zero IF; 1: low IF */ | ||
1674 | u32 Bandwidth, /* filter channel bandwidth (6, 7, 8) */ | ||
1675 | u32 IF_out, /* Desired IF Out Frequency */ | ||
1676 | u32 Fxtal, /* XTAL Frequency */ | ||
1677 | u8 AGC_Mode, /* AGC Mode - Dual AGC: 0, Single AGC: 1 */ | ||
1678 | u16 TOP, /* 0: Dual AGC; Value: take over point */ | ||
1679 | u16 IF_OUT_LOAD, /* IF Out Load Resistor (200 / 300 Ohms) */ | ||
1680 | u8 CLOCK_OUT, /* 0: turn off clk out; 1: turn on clock out */ | ||
1681 | u8 DIV_OUT, /* 0: Div-1; 1: Div-4 */ | ||
1682 | u8 CAPSELECT, /* 0: disable On-Chip pulling cap; 1: enable */ | ||
1683 | u8 EN_RSSI, /* 0: disable RSSI; 1: enable RSSI */ | ||
1684 | |||
1685 | /* Modulation Type; */ | ||
1686 | /* 0 - Default; 1 - DVB-T; 2 - ATSC; 3 - QAM; 4 - Analog Cable */ | ||
1687 | u8 Mod_Type, | ||
1688 | |||
1689 | /* Tracking Filter */ | ||
1690 | /* 0 - Default; 1 - Off; 2 - Type C; 3 - Type C-H */ | ||
1691 | u8 TF_Type | ||
1692 | ) | ||
1693 | { | ||
1694 | struct mxl5005s_state *state = fe->tuner_priv; | ||
1695 | u16 status = 0; | ||
1696 | |||
1697 | state->Mode = Mode; | ||
1698 | state->IF_Mode = IF_mode; | ||
1699 | state->Chan_Bandwidth = Bandwidth; | ||
1700 | state->IF_OUT = IF_out; | ||
1701 | state->Fxtal = Fxtal; | ||
1702 | state->AGC_Mode = AGC_Mode; | ||
1703 | state->TOP = TOP; | ||
1704 | state->IF_OUT_LOAD = IF_OUT_LOAD; | ||
1705 | state->CLOCK_OUT = CLOCK_OUT; | ||
1706 | state->DIV_OUT = DIV_OUT; | ||
1707 | state->CAPSELECT = CAPSELECT; | ||
1708 | state->EN_RSSI = EN_RSSI; | ||
1709 | state->Mod_Type = Mod_Type; | ||
1710 | state->TF_Type = TF_Type; | ||
1711 | |||
1712 | /* Initialize all the controls and registers */ | ||
1713 | InitTunerControls(fe); | ||
1714 | |||
1715 | /* Synthesizer LO frequency calculation */ | ||
1716 | MXL_SynthIFLO_Calc(fe); | ||
1717 | |||
1718 | return status; | ||
1719 | } | ||
1720 | |||
1721 | static void MXL_SynthIFLO_Calc(struct dvb_frontend *fe) | ||
1722 | { | ||
1723 | struct mxl5005s_state *state = fe->tuner_priv; | ||
1724 | if (state->Mode == 1) /* Digital Mode */ | ||
1725 | state->IF_LO = state->IF_OUT; | ||
1726 | else /* Analog Mode */ { | ||
1727 | if (state->IF_Mode == 0) /* Analog Zero IF mode */ | ||
1728 | state->IF_LO = state->IF_OUT + 400000; | ||
1729 | else /* Analog Low IF mode */ | ||
1730 | state->IF_LO = state->IF_OUT + state->Chan_Bandwidth/2; | ||
1731 | } | ||
1732 | } | ||
1733 | |||
1734 | static void MXL_SynthRFTGLO_Calc(struct dvb_frontend *fe) | ||
1735 | { | ||
1736 | struct mxl5005s_state *state = fe->tuner_priv; | ||
1737 | |||
1738 | if (state->Mode == 1) /* Digital Mode */ { | ||
1739 | /* remove 20.48MHz setting for 2.6.10 */ | ||
1740 | state->RF_LO = state->RF_IN; | ||
1741 | /* change for 2.6.6 */ | ||
1742 | state->TG_LO = state->RF_IN - 750000; | ||
1743 | } else /* Analog Mode */ { | ||
1744 | if (state->IF_Mode == 0) /* Analog Zero IF mode */ { | ||
1745 | state->RF_LO = state->RF_IN - 400000; | ||
1746 | state->TG_LO = state->RF_IN - 1750000; | ||
1747 | } else /* Analog Low IF mode */ { | ||
1748 | state->RF_LO = state->RF_IN - state->Chan_Bandwidth/2; | ||
1749 | state->TG_LO = state->RF_IN - | ||
1750 | state->Chan_Bandwidth + 500000; | ||
1751 | } | ||
1752 | } | ||
1753 | } | ||
1754 | |||
1755 | static u16 MXL_OverwriteICDefault(struct dvb_frontend *fe) | ||
1756 | { | ||
1757 | u16 status = 0; | ||
1758 | |||
1759 | status += MXL_ControlWrite(fe, OVERRIDE_1, 1); | ||
1760 | status += MXL_ControlWrite(fe, OVERRIDE_2, 1); | ||
1761 | status += MXL_ControlWrite(fe, OVERRIDE_3, 1); | ||
1762 | status += MXL_ControlWrite(fe, OVERRIDE_4, 1); | ||
1763 | |||
1764 | return status; | ||
1765 | } | ||
1766 | |||
1767 | static u16 MXL_BlockInit(struct dvb_frontend *fe) | ||
1768 | { | ||
1769 | struct mxl5005s_state *state = fe->tuner_priv; | ||
1770 | u16 status = 0; | ||
1771 | |||
1772 | status += MXL_OverwriteICDefault(fe); | ||
1773 | |||
1774 | /* Downconverter Control Dig Ana */ | ||
1775 | status += MXL_ControlWrite(fe, DN_IQTN_AMP_CUT, state->Mode ? 1 : 0); | ||
1776 | |||
1777 | /* Filter Control Dig Ana */ | ||
1778 | status += MXL_ControlWrite(fe, BB_MODE, state->Mode ? 0 : 1); | ||
1779 | status += MXL_ControlWrite(fe, BB_BUF, state->Mode ? 3 : 2); | ||
1780 | status += MXL_ControlWrite(fe, BB_BUF_OA, state->Mode ? 1 : 0); | ||
1781 | status += MXL_ControlWrite(fe, BB_IQSWAP, state->Mode ? 0 : 1); | ||
1782 | status += MXL_ControlWrite(fe, BB_INITSTATE_DLPF_TUNE, 0); | ||
1783 | |||
1784 | /* Initialize Low-Pass Filter */ | ||
1785 | if (state->Mode) { /* Digital Mode */ | ||
1786 | switch (state->Chan_Bandwidth) { | ||
1787 | case 8000000: | ||
1788 | status += MXL_ControlWrite(fe, BB_DLPF_BANDSEL, 0); | ||
1789 | break; | ||
1790 | case 7000000: | ||
1791 | status += MXL_ControlWrite(fe, BB_DLPF_BANDSEL, 2); | ||
1792 | break; | ||
1793 | case 6000000: | ||
1794 | status += MXL_ControlWrite(fe, | ||
1795 | BB_DLPF_BANDSEL, 3); | ||
1796 | break; | ||
1797 | } | ||
1798 | } else { /* Analog Mode */ | ||
1799 | switch (state->Chan_Bandwidth) { | ||
1800 | case 8000000: /* Low Zero */ | ||
1801 | status += MXL_ControlWrite(fe, BB_ALPF_BANDSELECT, | ||
1802 | (state->IF_Mode ? 0 : 3)); | ||
1803 | break; | ||
1804 | case 7000000: | ||
1805 | status += MXL_ControlWrite(fe, BB_ALPF_BANDSELECT, | ||
1806 | (state->IF_Mode ? 1 : 4)); | ||
1807 | break; | ||
1808 | case 6000000: | ||
1809 | status += MXL_ControlWrite(fe, BB_ALPF_BANDSELECT, | ||
1810 | (state->IF_Mode ? 2 : 5)); | ||
1811 | break; | ||
1812 | } | ||
1813 | } | ||
1814 | |||
1815 | /* Charge Pump Control Dig Ana */ | ||
1816 | status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, state->Mode ? 5 : 8); | ||
1817 | status += MXL_ControlWrite(fe, | ||
1818 | RFSYN_EN_CHP_HIGAIN, state->Mode ? 1 : 1); | ||
1819 | status += MXL_ControlWrite(fe, EN_CHP_LIN_B, state->Mode ? 0 : 0); | ||
1820 | |||
1821 | /* AGC TOP Control */ | ||
1822 | if (state->AGC_Mode == 0) /* Dual AGC */ { | ||
1823 | status += MXL_ControlWrite(fe, AGC_IF, 15); | ||
1824 | status += MXL_ControlWrite(fe, AGC_RF, 15); | ||
1825 | } else /* Single AGC Mode Dig Ana */ | ||
1826 | status += MXL_ControlWrite(fe, AGC_RF, state->Mode ? 15 : 12); | ||
1827 | |||
1828 | if (state->TOP == 55) /* TOP == 5.5 */ | ||
1829 | status += MXL_ControlWrite(fe, AGC_IF, 0x0); | ||
1830 | |||
1831 | if (state->TOP == 72) /* TOP == 7.2 */ | ||
1832 | status += MXL_ControlWrite(fe, AGC_IF, 0x1); | ||
1833 | |||
1834 | if (state->TOP == 92) /* TOP == 9.2 */ | ||
1835 | status += MXL_ControlWrite(fe, AGC_IF, 0x2); | ||
1836 | |||
1837 | if (state->TOP == 110) /* TOP == 11.0 */ | ||
1838 | status += MXL_ControlWrite(fe, AGC_IF, 0x3); | ||
1839 | |||
1840 | if (state->TOP == 129) /* TOP == 12.9 */ | ||
1841 | status += MXL_ControlWrite(fe, AGC_IF, 0x4); | ||
1842 | |||
1843 | if (state->TOP == 147) /* TOP == 14.7 */ | ||
1844 | status += MXL_ControlWrite(fe, AGC_IF, 0x5); | ||
1845 | |||
1846 | if (state->TOP == 168) /* TOP == 16.8 */ | ||
1847 | status += MXL_ControlWrite(fe, AGC_IF, 0x6); | ||
1848 | |||
1849 | if (state->TOP == 194) /* TOP == 19.4 */ | ||
1850 | status += MXL_ControlWrite(fe, AGC_IF, 0x7); | ||
1851 | |||
1852 | if (state->TOP == 212) /* TOP == 21.2 */ | ||
1853 | status += MXL_ControlWrite(fe, AGC_IF, 0x9); | ||
1854 | |||
1855 | if (state->TOP == 232) /* TOP == 23.2 */ | ||
1856 | status += MXL_ControlWrite(fe, AGC_IF, 0xA); | ||
1857 | |||
1858 | if (state->TOP == 252) /* TOP == 25.2 */ | ||
1859 | status += MXL_ControlWrite(fe, AGC_IF, 0xB); | ||
1860 | |||
1861 | if (state->TOP == 271) /* TOP == 27.1 */ | ||
1862 | status += MXL_ControlWrite(fe, AGC_IF, 0xC); | ||
1863 | |||
1864 | if (state->TOP == 292) /* TOP == 29.2 */ | ||
1865 | status += MXL_ControlWrite(fe, AGC_IF, 0xD); | ||
1866 | |||
1867 | if (state->TOP == 317) /* TOP == 31.7 */ | ||
1868 | status += MXL_ControlWrite(fe, AGC_IF, 0xE); | ||
1869 | |||
1870 | if (state->TOP == 349) /* TOP == 34.9 */ | ||
1871 | status += MXL_ControlWrite(fe, AGC_IF, 0xF); | ||
1872 | |||
1873 | /* IF Synthesizer Control */ | ||
1874 | status += MXL_IFSynthInit(fe); | ||
1875 | |||
1876 | /* IF UpConverter Control */ | ||
1877 | if (state->IF_OUT_LOAD == 200) { | ||
1878 | status += MXL_ControlWrite(fe, DRV_RES_SEL, 6); | ||
1879 | status += MXL_ControlWrite(fe, I_DRIVER, 2); | ||
1880 | } | ||
1881 | if (state->IF_OUT_LOAD == 300) { | ||
1882 | status += MXL_ControlWrite(fe, DRV_RES_SEL, 4); | ||
1883 | status += MXL_ControlWrite(fe, I_DRIVER, 1); | ||
1884 | } | ||
1885 | |||
1886 | /* Anti-Alias Filtering Control | ||
1887 | * initialise Anti-Aliasing Filter | ||
1888 | */ | ||
1889 | if (state->Mode) { /* Digital Mode */ | ||
1890 | if (state->IF_OUT >= 4000000UL && state->IF_OUT <= 6280000UL) { | ||
1891 | status += MXL_ControlWrite(fe, EN_AAF, 1); | ||
1892 | status += MXL_ControlWrite(fe, EN_3P, 1); | ||
1893 | status += MXL_ControlWrite(fe, EN_AUX_3P, 1); | ||
1894 | status += MXL_ControlWrite(fe, SEL_AAF_BAND, 0); | ||
1895 | } | ||
1896 | if ((state->IF_OUT == 36125000UL) || | ||
1897 | (state->IF_OUT == 36150000UL)) { | ||
1898 | status += MXL_ControlWrite(fe, EN_AAF, 1); | ||
1899 | status += MXL_ControlWrite(fe, EN_3P, 1); | ||
1900 | status += MXL_ControlWrite(fe, EN_AUX_3P, 1); | ||
1901 | status += MXL_ControlWrite(fe, SEL_AAF_BAND, 1); | ||
1902 | } | ||
1903 | if (state->IF_OUT > 36150000UL) { | ||
1904 | status += MXL_ControlWrite(fe, EN_AAF, 0); | ||
1905 | status += MXL_ControlWrite(fe, EN_3P, 1); | ||
1906 | status += MXL_ControlWrite(fe, EN_AUX_3P, 1); | ||
1907 | status += MXL_ControlWrite(fe, SEL_AAF_BAND, 1); | ||
1908 | } | ||
1909 | } else { /* Analog Mode */ | ||
1910 | if (state->IF_OUT >= 4000000UL && state->IF_OUT <= 5000000UL) { | ||
1911 | status += MXL_ControlWrite(fe, EN_AAF, 1); | ||
1912 | status += MXL_ControlWrite(fe, EN_3P, 1); | ||
1913 | status += MXL_ControlWrite(fe, EN_AUX_3P, 1); | ||
1914 | status += MXL_ControlWrite(fe, SEL_AAF_BAND, 0); | ||
1915 | } | ||
1916 | if (state->IF_OUT > 5000000UL) { | ||
1917 | status += MXL_ControlWrite(fe, EN_AAF, 0); | ||
1918 | status += MXL_ControlWrite(fe, EN_3P, 0); | ||
1919 | status += MXL_ControlWrite(fe, EN_AUX_3P, 0); | ||
1920 | status += MXL_ControlWrite(fe, SEL_AAF_BAND, 0); | ||
1921 | } | ||
1922 | } | ||
1923 | |||
1924 | /* Demod Clock Out */ | ||
1925 | if (state->CLOCK_OUT) | ||
1926 | status += MXL_ControlWrite(fe, SEQ_ENCLK16_CLK_OUT, 1); | ||
1927 | else | ||
1928 | status += MXL_ControlWrite(fe, SEQ_ENCLK16_CLK_OUT, 0); | ||
1929 | |||
1930 | if (state->DIV_OUT == 1) | ||
1931 | status += MXL_ControlWrite(fe, SEQ_SEL4_16B, 1); | ||
1932 | if (state->DIV_OUT == 0) | ||
1933 | status += MXL_ControlWrite(fe, SEQ_SEL4_16B, 0); | ||
1934 | |||
1935 | /* Crystal Control */ | ||
1936 | if (state->CAPSELECT) | ||
1937 | status += MXL_ControlWrite(fe, XTAL_CAPSELECT, 1); | ||
1938 | else | ||
1939 | status += MXL_ControlWrite(fe, XTAL_CAPSELECT, 0); | ||
1940 | |||
1941 | if (state->Fxtal >= 12000000UL && state->Fxtal <= 16000000UL) | ||
1942 | status += MXL_ControlWrite(fe, IF_SEL_DBL, 1); | ||
1943 | if (state->Fxtal > 16000000UL && state->Fxtal <= 32000000UL) | ||
1944 | status += MXL_ControlWrite(fe, IF_SEL_DBL, 0); | ||
1945 | |||
1946 | if (state->Fxtal >= 12000000UL && state->Fxtal <= 22000000UL) | ||
1947 | status += MXL_ControlWrite(fe, RFSYN_R_DIV, 3); | ||
1948 | if (state->Fxtal > 22000000UL && state->Fxtal <= 32000000UL) | ||
1949 | status += MXL_ControlWrite(fe, RFSYN_R_DIV, 0); | ||
1950 | |||
1951 | /* Misc Controls */ | ||
1952 | if (state->Mode == 0 && state->IF_Mode == 1) /* Analog LowIF mode */ | ||
1953 | status += MXL_ControlWrite(fe, SEQ_EXTIQFSMPULSE, 0); | ||
1954 | else | ||
1955 | status += MXL_ControlWrite(fe, SEQ_EXTIQFSMPULSE, 1); | ||
1956 | |||
1957 | /* status += MXL_ControlRead(fe, IF_DIVVAL, &IF_DIVVAL_Val); */ | ||
1958 | |||
1959 | /* Set TG_R_DIV */ | ||
1960 | status += MXL_ControlWrite(fe, TG_R_DIV, | ||
1961 | MXL_Ceiling(state->Fxtal, 1000000)); | ||
1962 | |||
1963 | /* Apply Default value to BB_INITSTATE_DLPF_TUNE */ | ||
1964 | |||
1965 | /* RSSI Control */ | ||
1966 | if (state->EN_RSSI) { | ||
1967 | status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); | ||
1968 | status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); | ||
1969 | status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1); | ||
1970 | status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); | ||
1971 | |||
1972 | /* RSSI reference point */ | ||
1973 | status += MXL_ControlWrite(fe, RFA_RSSI_REF, 2); | ||
1974 | status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 3); | ||
1975 | status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 1); | ||
1976 | |||
1977 | /* TOP point */ | ||
1978 | status += MXL_ControlWrite(fe, RFA_FLR, 0); | ||
1979 | status += MXL_ControlWrite(fe, RFA_CEIL, 12); | ||
1980 | } | ||
1981 | |||
1982 | /* Modulation type bit settings | ||
1983 | * Override the control values preset | ||
1984 | */ | ||
1985 | if (state->Mod_Type == MXL_DVBT) /* DVB-T Mode */ { | ||
1986 | state->AGC_Mode = 1; /* Single AGC Mode */ | ||
1987 | |||
1988 | /* Enable RSSI */ | ||
1989 | status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); | ||
1990 | status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); | ||
1991 | status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1); | ||
1992 | status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); | ||
1993 | |||
1994 | /* RSSI reference point */ | ||
1995 | status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3); | ||
1996 | status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5); | ||
1997 | status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 1); | ||
1998 | |||
1999 | /* TOP point */ | ||
2000 | status += MXL_ControlWrite(fe, RFA_FLR, 2); | ||
2001 | status += MXL_ControlWrite(fe, RFA_CEIL, 13); | ||
2002 | if (state->IF_OUT <= 6280000UL) /* Low IF */ | ||
2003 | status += MXL_ControlWrite(fe, BB_IQSWAP, 0); | ||
2004 | else /* High IF */ | ||
2005 | status += MXL_ControlWrite(fe, BB_IQSWAP, 1); | ||
2006 | |||
2007 | } | ||
2008 | if (state->Mod_Type == MXL_ATSC) /* ATSC Mode */ { | ||
2009 | state->AGC_Mode = 1; /* Single AGC Mode */ | ||
2010 | |||
2011 | /* Enable RSSI */ | ||
2012 | status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); | ||
2013 | status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); | ||
2014 | status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1); | ||
2015 | status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); | ||
2016 | |||
2017 | /* RSSI reference point */ | ||
2018 | status += MXL_ControlWrite(fe, RFA_RSSI_REF, 2); | ||
2019 | status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 4); | ||
2020 | status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 1); | ||
2021 | |||
2022 | /* TOP point */ | ||
2023 | status += MXL_ControlWrite(fe, RFA_FLR, 2); | ||
2024 | status += MXL_ControlWrite(fe, RFA_CEIL, 13); | ||
2025 | status += MXL_ControlWrite(fe, BB_INITSTATE_DLPF_TUNE, 1); | ||
2026 | /* Low Zero */ | ||
2027 | status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 5); | ||
2028 | |||
2029 | if (state->IF_OUT <= 6280000UL) /* Low IF */ | ||
2030 | status += MXL_ControlWrite(fe, BB_IQSWAP, 0); | ||
2031 | else /* High IF */ | ||
2032 | status += MXL_ControlWrite(fe, BB_IQSWAP, 1); | ||
2033 | } | ||
2034 | if (state->Mod_Type == MXL_QAM) /* QAM Mode */ { | ||
2035 | state->Mode = MXL_DIGITAL_MODE; | ||
2036 | |||
2037 | /* state->AGC_Mode = 1; */ /* Single AGC Mode */ | ||
2038 | |||
2039 | /* Disable RSSI */ /* change here for v2.6.5 */ | ||
2040 | status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); | ||
2041 | status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); | ||
2042 | status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0); | ||
2043 | status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); | ||
2044 | |||
2045 | /* RSSI reference point */ | ||
2046 | status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5); | ||
2047 | status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3); | ||
2048 | status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 2); | ||
2049 | /* change here for v2.6.5 */ | ||
2050 | status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3); | ||
2051 | |||
2052 | if (state->IF_OUT <= 6280000UL) /* Low IF */ | ||
2053 | status += MXL_ControlWrite(fe, BB_IQSWAP, 0); | ||
2054 | else /* High IF */ | ||
2055 | status += MXL_ControlWrite(fe, BB_IQSWAP, 1); | ||
2056 | status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 2); | ||
2057 | |||
2058 | } | ||
2059 | if (state->Mod_Type == MXL_ANALOG_CABLE) { | ||
2060 | /* Analog Cable Mode */ | ||
2061 | /* state->Mode = MXL_DIGITAL_MODE; */ | ||
2062 | |||
2063 | state->AGC_Mode = 1; /* Single AGC Mode */ | ||
2064 | |||
2065 | /* Disable RSSI */ | ||
2066 | status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); | ||
2067 | status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); | ||
2068 | status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0); | ||
2069 | status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); | ||
2070 | /* change for 2.6.3 */ | ||
2071 | status += MXL_ControlWrite(fe, AGC_IF, 1); | ||
2072 | status += MXL_ControlWrite(fe, AGC_RF, 15); | ||
2073 | status += MXL_ControlWrite(fe, BB_IQSWAP, 1); | ||
2074 | } | ||
2075 | |||
2076 | if (state->Mod_Type == MXL_ANALOG_OTA) { | ||
2077 | /* Analog OTA Terrestrial mode add for 2.6.7 */ | ||
2078 | /* state->Mode = MXL_ANALOG_MODE; */ | ||
2079 | |||
2080 | /* Enable RSSI */ | ||
2081 | status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); | ||
2082 | status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); | ||
2083 | status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1); | ||
2084 | status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); | ||
2085 | |||
2086 | /* RSSI reference point */ | ||
2087 | status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5); | ||
2088 | status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3); | ||
2089 | status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 2); | ||
2090 | status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3); | ||
2091 | status += MXL_ControlWrite(fe, BB_IQSWAP, 1); | ||
2092 | } | ||
2093 | |||
2094 | /* RSSI disable */ | ||
2095 | if (state->EN_RSSI == 0) { | ||
2096 | status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); | ||
2097 | status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); | ||
2098 | status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0); | ||
2099 | status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); | ||
2100 | } | ||
2101 | |||
2102 | return status; | ||
2103 | } | ||
2104 | |||
2105 | static u16 MXL_IFSynthInit(struct dvb_frontend *fe) | ||
2106 | { | ||
2107 | struct mxl5005s_state *state = fe->tuner_priv; | ||
2108 | u16 status = 0 ; | ||
2109 | u32 Fref = 0 ; | ||
2110 | u32 Kdbl, intModVal ; | ||
2111 | u32 fracModVal ; | ||
2112 | Kdbl = 2 ; | ||
2113 | |||
2114 | if (state->Fxtal >= 12000000UL && state->Fxtal <= 16000000UL) | ||
2115 | Kdbl = 2 ; | ||
2116 | if (state->Fxtal > 16000000UL && state->Fxtal <= 32000000UL) | ||
2117 | Kdbl = 1 ; | ||
2118 | |||
2119 | /* IF Synthesizer Control */ | ||
2120 | if (state->Mode == 0 && state->IF_Mode == 1) /* Analog Low IF mode */ { | ||
2121 | if (state->IF_LO == 41000000UL) { | ||
2122 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); | ||
2123 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); | ||
2124 | Fref = 328000000UL ; | ||
2125 | } | ||
2126 | if (state->IF_LO == 47000000UL) { | ||
2127 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); | ||
2128 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
2129 | Fref = 376000000UL ; | ||
2130 | } | ||
2131 | if (state->IF_LO == 54000000UL) { | ||
2132 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x10); | ||
2133 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); | ||
2134 | Fref = 324000000UL ; | ||
2135 | } | ||
2136 | if (state->IF_LO == 60000000UL) { | ||
2137 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x10); | ||
2138 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
2139 | Fref = 360000000UL ; | ||
2140 | } | ||
2141 | if (state->IF_LO == 39250000UL) { | ||
2142 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); | ||
2143 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); | ||
2144 | Fref = 314000000UL ; | ||
2145 | } | ||
2146 | if (state->IF_LO == 39650000UL) { | ||
2147 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); | ||
2148 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); | ||
2149 | Fref = 317200000UL ; | ||
2150 | } | ||
2151 | if (state->IF_LO == 40150000UL) { | ||
2152 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); | ||
2153 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); | ||
2154 | Fref = 321200000UL ; | ||
2155 | } | ||
2156 | if (state->IF_LO == 40650000UL) { | ||
2157 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); | ||
2158 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); | ||
2159 | Fref = 325200000UL ; | ||
2160 | } | ||
2161 | } | ||
2162 | |||
2163 | if (state->Mode || (state->Mode == 0 && state->IF_Mode == 0)) { | ||
2164 | if (state->IF_LO == 57000000UL) { | ||
2165 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x10); | ||
2166 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
2167 | Fref = 342000000UL ; | ||
2168 | } | ||
2169 | if (state->IF_LO == 44000000UL) { | ||
2170 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); | ||
2171 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
2172 | Fref = 352000000UL ; | ||
2173 | } | ||
2174 | if (state->IF_LO == 43750000UL) { | ||
2175 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); | ||
2176 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
2177 | Fref = 350000000UL ; | ||
2178 | } | ||
2179 | if (state->IF_LO == 36650000UL) { | ||
2180 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); | ||
2181 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
2182 | Fref = 366500000UL ; | ||
2183 | } | ||
2184 | if (state->IF_LO == 36150000UL) { | ||
2185 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); | ||
2186 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
2187 | Fref = 361500000UL ; | ||
2188 | } | ||
2189 | if (state->IF_LO == 36000000UL) { | ||
2190 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); | ||
2191 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
2192 | Fref = 360000000UL ; | ||
2193 | } | ||
2194 | if (state->IF_LO == 35250000UL) { | ||
2195 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); | ||
2196 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
2197 | Fref = 352500000UL ; | ||
2198 | } | ||
2199 | if (state->IF_LO == 34750000UL) { | ||
2200 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); | ||
2201 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
2202 | Fref = 347500000UL ; | ||
2203 | } | ||
2204 | if (state->IF_LO == 6280000UL) { | ||
2205 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x07); | ||
2206 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
2207 | Fref = 376800000UL ; | ||
2208 | } | ||
2209 | if (state->IF_LO == 5000000UL) { | ||
2210 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x09); | ||
2211 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
2212 | Fref = 360000000UL ; | ||
2213 | } | ||
2214 | if (state->IF_LO == 4500000UL) { | ||
2215 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x06); | ||
2216 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
2217 | Fref = 360000000UL ; | ||
2218 | } | ||
2219 | if (state->IF_LO == 4570000UL) { | ||
2220 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x06); | ||
2221 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
2222 | Fref = 365600000UL ; | ||
2223 | } | ||
2224 | if (state->IF_LO == 4000000UL) { | ||
2225 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x05); | ||
2226 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
2227 | Fref = 360000000UL ; | ||
2228 | } | ||
2229 | if (state->IF_LO == 57400000UL) { | ||
2230 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x10); | ||
2231 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
2232 | Fref = 344400000UL ; | ||
2233 | } | ||
2234 | if (state->IF_LO == 44400000UL) { | ||
2235 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); | ||
2236 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
2237 | Fref = 355200000UL ; | ||
2238 | } | ||
2239 | if (state->IF_LO == 44150000UL) { | ||
2240 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x08); | ||
2241 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
2242 | Fref = 353200000UL ; | ||
2243 | } | ||
2244 | if (state->IF_LO == 37050000UL) { | ||
2245 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); | ||
2246 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
2247 | Fref = 370500000UL ; | ||
2248 | } | ||
2249 | if (state->IF_LO == 36550000UL) { | ||
2250 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); | ||
2251 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
2252 | Fref = 365500000UL ; | ||
2253 | } | ||
2254 | if (state->IF_LO == 36125000UL) { | ||
2255 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x04); | ||
2256 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
2257 | Fref = 361250000UL ; | ||
2258 | } | ||
2259 | if (state->IF_LO == 6000000UL) { | ||
2260 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x07); | ||
2261 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
2262 | Fref = 360000000UL ; | ||
2263 | } | ||
2264 | if (state->IF_LO == 5400000UL) { | ||
2265 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x07); | ||
2266 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); | ||
2267 | Fref = 324000000UL ; | ||
2268 | } | ||
2269 | if (state->IF_LO == 5380000UL) { | ||
2270 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x07); | ||
2271 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C); | ||
2272 | Fref = 322800000UL ; | ||
2273 | } | ||
2274 | if (state->IF_LO == 5200000UL) { | ||
2275 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x09); | ||
2276 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
2277 | Fref = 374400000UL ; | ||
2278 | } | ||
2279 | if (state->IF_LO == 4900000UL) { | ||
2280 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x09); | ||
2281 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
2282 | Fref = 352800000UL ; | ||
2283 | } | ||
2284 | if (state->IF_LO == 4400000UL) { | ||
2285 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x06); | ||
2286 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
2287 | Fref = 352000000UL ; | ||
2288 | } | ||
2289 | if (state->IF_LO == 4063000UL) /* add for 2.6.8 */ { | ||
2290 | status += MXL_ControlWrite(fe, IF_DIVVAL, 0x05); | ||
2291 | status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x08); | ||
2292 | Fref = 365670000UL ; | ||
2293 | } | ||
2294 | } | ||
2295 | /* CHCAL_INT_MOD_IF */ | ||
2296 | /* CHCAL_FRAC_MOD_IF */ | ||
2297 | intModVal = Fref / (state->Fxtal * Kdbl/2); | ||
2298 | status += MXL_ControlWrite(fe, CHCAL_INT_MOD_IF, intModVal); | ||
2299 | |||
2300 | fracModVal = (2<<15)*(Fref/1000 - (state->Fxtal/1000 * Kdbl/2) * | ||
2301 | intModVal); | ||
2302 | |||
2303 | fracModVal = fracModVal / ((state->Fxtal * Kdbl/2)/1000); | ||
2304 | status += MXL_ControlWrite(fe, CHCAL_FRAC_MOD_IF, fracModVal); | ||
2305 | |||
2306 | return status ; | ||
2307 | } | ||
2308 | |||
2309 | static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq) | ||
2310 | { | ||
2311 | struct mxl5005s_state *state = fe->tuner_priv; | ||
2312 | u16 status = 0; | ||
2313 | u32 divider_val, E3, E4, E5, E5A; | ||
2314 | u32 Fmax, Fmin, FmaxBin, FminBin; | ||
2315 | u32 Kdbl_RF = 2; | ||
2316 | u32 tg_divval; | ||
2317 | u32 tg_lo; | ||
2318 | |||
2319 | u32 Fref_TG; | ||
2320 | u32 Fvco; | ||
2321 | |||
2322 | state->RF_IN = RF_Freq; | ||
2323 | |||
2324 | MXL_SynthRFTGLO_Calc(fe); | ||
2325 | |||
2326 | if (state->Fxtal >= 12000000UL && state->Fxtal <= 22000000UL) | ||
2327 | Kdbl_RF = 2; | ||
2328 | if (state->Fxtal > 22000000 && state->Fxtal <= 32000000) | ||
2329 | Kdbl_RF = 1; | ||
2330 | |||
2331 | /* Downconverter Controls | ||
2332 | * Look-Up Table Implementation for: | ||
2333 | * DN_POLY | ||
2334 | * DN_RFGAIN | ||
2335 | * DN_CAP_RFLPF | ||
2336 | * DN_EN_VHFUHFBAR | ||
2337 | * DN_GAIN_ADJUST | ||
2338 | * Change the boundary reference from RF_IN to RF_LO | ||
2339 | */ | ||
2340 | if (state->RF_LO < 40000000UL) | ||
2341 | return -1; | ||
2342 | |||
2343 | if (state->RF_LO >= 40000000UL && state->RF_LO <= 75000000UL) { | ||
2344 | status += MXL_ControlWrite(fe, DN_POLY, 2); | ||
2345 | status += MXL_ControlWrite(fe, DN_RFGAIN, 3); | ||
2346 | status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 423); | ||
2347 | status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 1); | ||
2348 | status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 1); | ||
2349 | } | ||
2350 | if (state->RF_LO > 75000000UL && state->RF_LO <= 100000000UL) { | ||
2351 | status += MXL_ControlWrite(fe, DN_POLY, 3); | ||
2352 | status += MXL_ControlWrite(fe, DN_RFGAIN, 3); | ||
2353 | status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 222); | ||
2354 | status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 1); | ||
2355 | status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 1); | ||
2356 | } | ||
2357 | if (state->RF_LO > 100000000UL && state->RF_LO <= 150000000UL) { | ||
2358 | status += MXL_ControlWrite(fe, DN_POLY, 3); | ||
2359 | status += MXL_ControlWrite(fe, DN_RFGAIN, 3); | ||
2360 | status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 147); | ||
2361 | status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 1); | ||
2362 | status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 2); | ||
2363 | } | ||
2364 | if (state->RF_LO > 150000000UL && state->RF_LO <= 200000000UL) { | ||
2365 | status += MXL_ControlWrite(fe, DN_POLY, 3); | ||
2366 | status += MXL_ControlWrite(fe, DN_RFGAIN, 3); | ||
2367 | status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 9); | ||
2368 | status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 1); | ||
2369 | status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 2); | ||
2370 | } | ||
2371 | if (state->RF_LO > 200000000UL && state->RF_LO <= 300000000UL) { | ||
2372 | status += MXL_ControlWrite(fe, DN_POLY, 3); | ||
2373 | status += MXL_ControlWrite(fe, DN_RFGAIN, 3); | ||
2374 | status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 0); | ||
2375 | status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 1); | ||
2376 | status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 3); | ||
2377 | } | ||
2378 | if (state->RF_LO > 300000000UL && state->RF_LO <= 650000000UL) { | ||
2379 | status += MXL_ControlWrite(fe, DN_POLY, 3); | ||
2380 | status += MXL_ControlWrite(fe, DN_RFGAIN, 1); | ||
2381 | status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 0); | ||
2382 | status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 0); | ||
2383 | status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 3); | ||
2384 | } | ||
2385 | if (state->RF_LO > 650000000UL && state->RF_LO <= 900000000UL) { | ||
2386 | status += MXL_ControlWrite(fe, DN_POLY, 3); | ||
2387 | status += MXL_ControlWrite(fe, DN_RFGAIN, 2); | ||
2388 | status += MXL_ControlWrite(fe, DN_CAP_RFLPF, 0); | ||
2389 | status += MXL_ControlWrite(fe, DN_EN_VHFUHFBAR, 0); | ||
2390 | status += MXL_ControlWrite(fe, DN_GAIN_ADJUST, 3); | ||
2391 | } | ||
2392 | if (state->RF_LO > 900000000UL) | ||
2393 | return -1; | ||
2394 | |||
2395 | /* DN_IQTNBUF_AMP */ | ||
2396 | /* DN_IQTNGNBFBIAS_BST */ | ||
2397 | if (state->RF_LO >= 40000000UL && state->RF_LO <= 75000000UL) { | ||
2398 | status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); | ||
2399 | status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); | ||
2400 | } | ||
2401 | if (state->RF_LO > 75000000UL && state->RF_LO <= 100000000UL) { | ||
2402 | status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); | ||
2403 | status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); | ||
2404 | } | ||
2405 | if (state->RF_LO > 100000000UL && state->RF_LO <= 150000000UL) { | ||
2406 | status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); | ||
2407 | status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); | ||
2408 | } | ||
2409 | if (state->RF_LO > 150000000UL && state->RF_LO <= 200000000UL) { | ||
2410 | status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); | ||
2411 | status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); | ||
2412 | } | ||
2413 | if (state->RF_LO > 200000000UL && state->RF_LO <= 300000000UL) { | ||
2414 | status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); | ||
2415 | status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); | ||
2416 | } | ||
2417 | if (state->RF_LO > 300000000UL && state->RF_LO <= 400000000UL) { | ||
2418 | status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); | ||
2419 | status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); | ||
2420 | } | ||
2421 | if (state->RF_LO > 400000000UL && state->RF_LO <= 450000000UL) { | ||
2422 | status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); | ||
2423 | status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); | ||
2424 | } | ||
2425 | if (state->RF_LO > 450000000UL && state->RF_LO <= 500000000UL) { | ||
2426 | status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); | ||
2427 | status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); | ||
2428 | } | ||
2429 | if (state->RF_LO > 500000000UL && state->RF_LO <= 550000000UL) { | ||
2430 | status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); | ||
2431 | status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); | ||
2432 | } | ||
2433 | if (state->RF_LO > 550000000UL && state->RF_LO <= 600000000UL) { | ||
2434 | status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); | ||
2435 | status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); | ||
2436 | } | ||
2437 | if (state->RF_LO > 600000000UL && state->RF_LO <= 650000000UL) { | ||
2438 | status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); | ||
2439 | status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); | ||
2440 | } | ||
2441 | if (state->RF_LO > 650000000UL && state->RF_LO <= 700000000UL) { | ||
2442 | status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); | ||
2443 | status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); | ||
2444 | } | ||
2445 | if (state->RF_LO > 700000000UL && state->RF_LO <= 750000000UL) { | ||
2446 | status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); | ||
2447 | status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); | ||
2448 | } | ||
2449 | if (state->RF_LO > 750000000UL && state->RF_LO <= 800000000UL) { | ||
2450 | status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 1); | ||
2451 | status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 0); | ||
2452 | } | ||
2453 | if (state->RF_LO > 800000000UL && state->RF_LO <= 850000000UL) { | ||
2454 | status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 10); | ||
2455 | status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 1); | ||
2456 | } | ||
2457 | if (state->RF_LO > 850000000UL && state->RF_LO <= 900000000UL) { | ||
2458 | status += MXL_ControlWrite(fe, DN_IQTNBUF_AMP, 10); | ||
2459 | status += MXL_ControlWrite(fe, DN_IQTNGNBFBIAS_BST, 1); | ||
2460 | } | ||
2461 | |||
2462 | /* | ||
2463 | * Set RF Synth and LO Path Control | ||
2464 | * | ||
2465 | * Look-Up table implementation for: | ||
2466 | * RFSYN_EN_OUTMUX | ||
2467 | * RFSYN_SEL_VCO_OUT | ||
2468 | * RFSYN_SEL_VCO_HI | ||
2469 | * RFSYN_SEL_DIVM | ||
2470 | * RFSYN_RF_DIV_BIAS | ||
2471 | * DN_SEL_FREQ | ||
2472 | * | ||
2473 | * Set divider_val, Fmax, Fmix to use in Equations | ||
2474 | */ | ||
2475 | FminBin = 28000000UL ; | ||
2476 | FmaxBin = 42500000UL ; | ||
2477 | if (state->RF_LO >= 40000000UL && state->RF_LO <= FmaxBin) { | ||
2478 | status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 1); | ||
2479 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 0); | ||
2480 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); | ||
2481 | status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); | ||
2482 | status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); | ||
2483 | status += MXL_ControlWrite(fe, DN_SEL_FREQ, 1); | ||
2484 | divider_val = 64 ; | ||
2485 | Fmax = FmaxBin ; | ||
2486 | Fmin = FminBin ; | ||
2487 | } | ||
2488 | FminBin = 42500000UL ; | ||
2489 | FmaxBin = 56000000UL ; | ||
2490 | if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { | ||
2491 | status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 1); | ||
2492 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 0); | ||
2493 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); | ||
2494 | status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); | ||
2495 | status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); | ||
2496 | status += MXL_ControlWrite(fe, DN_SEL_FREQ, 1); | ||
2497 | divider_val = 64 ; | ||
2498 | Fmax = FmaxBin ; | ||
2499 | Fmin = FminBin ; | ||
2500 | } | ||
2501 | FminBin = 56000000UL ; | ||
2502 | FmaxBin = 85000000UL ; | ||
2503 | if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { | ||
2504 | status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); | ||
2505 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); | ||
2506 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); | ||
2507 | status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); | ||
2508 | status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); | ||
2509 | status += MXL_ControlWrite(fe, DN_SEL_FREQ, 1); | ||
2510 | divider_val = 32 ; | ||
2511 | Fmax = FmaxBin ; | ||
2512 | Fmin = FminBin ; | ||
2513 | } | ||
2514 | FminBin = 85000000UL ; | ||
2515 | FmaxBin = 112000000UL ; | ||
2516 | if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { | ||
2517 | status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); | ||
2518 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); | ||
2519 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); | ||
2520 | status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); | ||
2521 | status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); | ||
2522 | status += MXL_ControlWrite(fe, DN_SEL_FREQ, 1); | ||
2523 | divider_val = 32 ; | ||
2524 | Fmax = FmaxBin ; | ||
2525 | Fmin = FminBin ; | ||
2526 | } | ||
2527 | FminBin = 112000000UL ; | ||
2528 | FmaxBin = 170000000UL ; | ||
2529 | if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { | ||
2530 | status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); | ||
2531 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); | ||
2532 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); | ||
2533 | status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); | ||
2534 | status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); | ||
2535 | status += MXL_ControlWrite(fe, DN_SEL_FREQ, 2); | ||
2536 | divider_val = 16 ; | ||
2537 | Fmax = FmaxBin ; | ||
2538 | Fmin = FminBin ; | ||
2539 | } | ||
2540 | FminBin = 170000000UL ; | ||
2541 | FmaxBin = 225000000UL ; | ||
2542 | if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { | ||
2543 | status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); | ||
2544 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); | ||
2545 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); | ||
2546 | status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); | ||
2547 | status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); | ||
2548 | status += MXL_ControlWrite(fe, DN_SEL_FREQ, 2); | ||
2549 | divider_val = 16 ; | ||
2550 | Fmax = FmaxBin ; | ||
2551 | Fmin = FminBin ; | ||
2552 | } | ||
2553 | FminBin = 225000000UL ; | ||
2554 | FmaxBin = 300000000UL ; | ||
2555 | if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { | ||
2556 | status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); | ||
2557 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); | ||
2558 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); | ||
2559 | status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); | ||
2560 | status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); | ||
2561 | status += MXL_ControlWrite(fe, DN_SEL_FREQ, 4); | ||
2562 | divider_val = 8 ; | ||
2563 | Fmax = 340000000UL ; | ||
2564 | Fmin = FminBin ; | ||
2565 | } | ||
2566 | FminBin = 300000000UL ; | ||
2567 | FmaxBin = 340000000UL ; | ||
2568 | if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { | ||
2569 | status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 1); | ||
2570 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 0); | ||
2571 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); | ||
2572 | status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); | ||
2573 | status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); | ||
2574 | status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); | ||
2575 | divider_val = 8 ; | ||
2576 | Fmax = FmaxBin ; | ||
2577 | Fmin = 225000000UL ; | ||
2578 | } | ||
2579 | FminBin = 340000000UL ; | ||
2580 | FmaxBin = 450000000UL ; | ||
2581 | if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { | ||
2582 | status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 1); | ||
2583 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 0); | ||
2584 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); | ||
2585 | status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); | ||
2586 | status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 2); | ||
2587 | status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); | ||
2588 | divider_val = 8 ; | ||
2589 | Fmax = FmaxBin ; | ||
2590 | Fmin = FminBin ; | ||
2591 | } | ||
2592 | FminBin = 450000000UL ; | ||
2593 | FmaxBin = 680000000UL ; | ||
2594 | if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { | ||
2595 | status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); | ||
2596 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); | ||
2597 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); | ||
2598 | status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 1); | ||
2599 | status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); | ||
2600 | status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); | ||
2601 | divider_val = 4 ; | ||
2602 | Fmax = FmaxBin ; | ||
2603 | Fmin = FminBin ; | ||
2604 | } | ||
2605 | FminBin = 680000000UL ; | ||
2606 | FmaxBin = 900000000UL ; | ||
2607 | if (state->RF_LO > FminBin && state->RF_LO <= FmaxBin) { | ||
2608 | status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); | ||
2609 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); | ||
2610 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); | ||
2611 | status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 1); | ||
2612 | status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); | ||
2613 | status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); | ||
2614 | divider_val = 4 ; | ||
2615 | Fmax = FmaxBin ; | ||
2616 | Fmin = FminBin ; | ||
2617 | } | ||
2618 | |||
2619 | /* CHCAL_INT_MOD_RF | ||
2620 | * CHCAL_FRAC_MOD_RF | ||
2621 | * RFSYN_LPF_R | ||
2622 | * CHCAL_EN_INT_RF | ||
2623 | */ | ||
2624 | /* Equation E3 RFSYN_VCO_BIAS */ | ||
2625 | E3 = (((Fmax-state->RF_LO)/1000)*32)/((Fmax-Fmin)/1000) + 8 ; | ||
2626 | status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, E3); | ||
2627 | |||
2628 | /* Equation E4 CHCAL_INT_MOD_RF */ | ||
2629 | E4 = (state->RF_LO*divider_val/1000)/(2*state->Fxtal*Kdbl_RF/1000); | ||
2630 | MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, E4); | ||
2631 | |||
2632 | /* Equation E5 CHCAL_FRAC_MOD_RF CHCAL_EN_INT_RF */ | ||
2633 | E5 = ((2<<17)*(state->RF_LO/10000*divider_val - | ||
2634 | (E4*(2*state->Fxtal*Kdbl_RF)/10000))) / | ||
2635 | (2*state->Fxtal*Kdbl_RF/10000); | ||
2636 | |||
2637 | status += MXL_ControlWrite(fe, CHCAL_FRAC_MOD_RF, E5); | ||
2638 | |||
2639 | /* Equation E5A RFSYN_LPF_R */ | ||
2640 | E5A = (((Fmax - state->RF_LO)/1000)*4/((Fmax-Fmin)/1000)) + 1 ; | ||
2641 | status += MXL_ControlWrite(fe, RFSYN_LPF_R, E5A); | ||
2642 | |||
2643 | /* Euqation E5B CHCAL_EN_INIT_RF */ | ||
2644 | status += MXL_ControlWrite(fe, CHCAL_EN_INT_RF, ((E5 == 0) ? 1 : 0)); | ||
2645 | /*if (E5 == 0) | ||
2646 | * status += MXL_ControlWrite(fe, CHCAL_EN_INT_RF, 1); | ||
2647 | *else | ||
2648 | * status += MXL_ControlWrite(fe, CHCAL_FRAC_MOD_RF, E5); | ||
2649 | */ | ||
2650 | |||
2651 | /* | ||
2652 | * Set TG Synth | ||
2653 | * | ||
2654 | * Look-Up table implementation for: | ||
2655 | * TG_LO_DIVVAL | ||
2656 | * TG_LO_SELVAL | ||
2657 | * | ||
2658 | * Set divider_val, Fmax, Fmix to use in Equations | ||
2659 | */ | ||
2660 | if (state->TG_LO < 33000000UL) | ||
2661 | return -1; | ||
2662 | |||
2663 | FminBin = 33000000UL ; | ||
2664 | FmaxBin = 50000000UL ; | ||
2665 | if (state->TG_LO >= FminBin && state->TG_LO <= FmaxBin) { | ||
2666 | status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x6); | ||
2667 | status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x0); | ||
2668 | divider_val = 36 ; | ||
2669 | Fmax = FmaxBin ; | ||
2670 | Fmin = FminBin ; | ||
2671 | } | ||
2672 | FminBin = 50000000UL ; | ||
2673 | FmaxBin = 67000000UL ; | ||
2674 | if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { | ||
2675 | status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x1); | ||
2676 | status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x0); | ||
2677 | divider_val = 24 ; | ||
2678 | Fmax = FmaxBin ; | ||
2679 | Fmin = FminBin ; | ||
2680 | } | ||
2681 | FminBin = 67000000UL ; | ||
2682 | FmaxBin = 100000000UL ; | ||
2683 | if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { | ||
2684 | status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0xC); | ||
2685 | status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x2); | ||
2686 | divider_val = 18 ; | ||
2687 | Fmax = FmaxBin ; | ||
2688 | Fmin = FminBin ; | ||
2689 | } | ||
2690 | FminBin = 100000000UL ; | ||
2691 | FmaxBin = 150000000UL ; | ||
2692 | if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { | ||
2693 | status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x8); | ||
2694 | status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x2); | ||
2695 | divider_val = 12 ; | ||
2696 | Fmax = FmaxBin ; | ||
2697 | Fmin = FminBin ; | ||
2698 | } | ||
2699 | FminBin = 150000000UL ; | ||
2700 | FmaxBin = 200000000UL ; | ||
2701 | if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { | ||
2702 | status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x0); | ||
2703 | status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x2); | ||
2704 | divider_val = 8 ; | ||
2705 | Fmax = FmaxBin ; | ||
2706 | Fmin = FminBin ; | ||
2707 | } | ||
2708 | FminBin = 200000000UL ; | ||
2709 | FmaxBin = 300000000UL ; | ||
2710 | if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { | ||
2711 | status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x8); | ||
2712 | status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x3); | ||
2713 | divider_val = 6 ; | ||
2714 | Fmax = FmaxBin ; | ||
2715 | Fmin = FminBin ; | ||
2716 | } | ||
2717 | FminBin = 300000000UL ; | ||
2718 | FmaxBin = 400000000UL ; | ||
2719 | if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { | ||
2720 | status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x0); | ||
2721 | status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x3); | ||
2722 | divider_val = 4 ; | ||
2723 | Fmax = FmaxBin ; | ||
2724 | Fmin = FminBin ; | ||
2725 | } | ||
2726 | FminBin = 400000000UL ; | ||
2727 | FmaxBin = 600000000UL ; | ||
2728 | if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { | ||
2729 | status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x8); | ||
2730 | status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x7); | ||
2731 | divider_val = 3 ; | ||
2732 | Fmax = FmaxBin ; | ||
2733 | Fmin = FminBin ; | ||
2734 | } | ||
2735 | FminBin = 600000000UL ; | ||
2736 | FmaxBin = 900000000UL ; | ||
2737 | if (state->TG_LO > FminBin && state->TG_LO <= FmaxBin) { | ||
2738 | status += MXL_ControlWrite(fe, TG_LO_DIVVAL, 0x0); | ||
2739 | status += MXL_ControlWrite(fe, TG_LO_SELVAL, 0x7); | ||
2740 | divider_val = 2 ; | ||
2741 | Fmax = FmaxBin ; | ||
2742 | Fmin = FminBin ; | ||
2743 | } | ||
2744 | |||
2745 | /* TG_DIV_VAL */ | ||
2746 | tg_divval = (state->TG_LO*divider_val/100000) * | ||
2747 | (MXL_Ceiling(state->Fxtal, 1000000) * 100) / | ||
2748 | (state->Fxtal/1000); | ||
2749 | |||
2750 | status += MXL_ControlWrite(fe, TG_DIV_VAL, tg_divval); | ||
2751 | |||
2752 | if (state->TG_LO > 600000000UL) | ||
2753 | status += MXL_ControlWrite(fe, TG_DIV_VAL, tg_divval + 1); | ||
2754 | |||
2755 | Fmax = 1800000000UL ; | ||
2756 | Fmin = 1200000000UL ; | ||
2757 | |||
2758 | /* prevent overflow of 32 bit unsigned integer, use | ||
2759 | * following equation. Edit for v2.6.4 | ||
2760 | */ | ||
2761 | /* Fref_TF = Fref_TG * 1000 */ | ||
2762 | Fref_TG = (state->Fxtal/1000) / MXL_Ceiling(state->Fxtal, 1000000); | ||
2763 | |||
2764 | /* Fvco = Fvco/10 */ | ||
2765 | Fvco = (state->TG_LO/10000) * divider_val * Fref_TG; | ||
2766 | |||
2767 | tg_lo = (((Fmax/10 - Fvco)/100)*32) / ((Fmax-Fmin)/1000)+8; | ||
2768 | |||
2769 | /* below equation is same as above but much harder to debug. | ||
2770 | * | ||
2771 | * static u32 MXL_GetXtalInt(u32 Xtal_Freq) | ||
2772 | * { | ||
2773 | * if ((Xtal_Freq % 1000000) == 0) | ||
2774 | * return (Xtal_Freq / 10000); | ||
2775 | * else | ||
2776 | * return (((Xtal_Freq / 1000000) + 1)*100); | ||
2777 | * } | ||
2778 | * | ||
2779 | * u32 Xtal_Int = MXL_GetXtalInt(state->Fxtal); | ||
2780 | * tg_lo = ( ((Fmax/10000 * Xtal_Int)/100) - | ||
2781 | * ((state->TG_LO/10000)*divider_val * | ||
2782 | * (state->Fxtal/10000)/100) )*32/((Fmax-Fmin)/10000 * | ||
2783 | * Xtal_Int/100) + 8; | ||
2784 | */ | ||
2785 | |||
2786 | status += MXL_ControlWrite(fe, TG_VCO_BIAS , tg_lo); | ||
2787 | |||
2788 | /* add for 2.6.5 Special setting for QAM */ | ||
2789 | if (state->Mod_Type == MXL_QAM) { | ||
2790 | if (state->config->qam_gain != 0) | ||
2791 | status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, | ||
2792 | state->config->qam_gain); | ||
2793 | else if (state->RF_IN < 680000000) | ||
2794 | status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3); | ||
2795 | else | ||
2796 | status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 2); | ||
2797 | } | ||
2798 | |||
2799 | /* Off Chip Tracking Filter Control */ | ||
2800 | if (state->TF_Type == MXL_TF_OFF) { | ||
2801 | /* Tracking Filter Off State; turn off all the banks */ | ||
2802 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); | ||
2803 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
2804 | status += MXL_SetGPIO(fe, 3, 1); /* Bank1 Off */ | ||
2805 | status += MXL_SetGPIO(fe, 1, 1); /* Bank2 Off */ | ||
2806 | status += MXL_SetGPIO(fe, 4, 1); /* Bank3 Off */ | ||
2807 | } | ||
2808 | |||
2809 | if (state->TF_Type == MXL_TF_C) /* Tracking Filter type C */ { | ||
2810 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); | ||
2811 | status += MXL_ControlWrite(fe, DAC_DIN_A, 0); | ||
2812 | |||
2813 | if (state->RF_IN >= 43000000 && state->RF_IN < 150000000) { | ||
2814 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); | ||
2815 | status += MXL_ControlWrite(fe, DAC_DIN_B, 0); | ||
2816 | status += MXL_SetGPIO(fe, 3, 0); | ||
2817 | status += MXL_SetGPIO(fe, 1, 1); | ||
2818 | status += MXL_SetGPIO(fe, 4, 1); | ||
2819 | } | ||
2820 | if (state->RF_IN >= 150000000 && state->RF_IN < 280000000) { | ||
2821 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); | ||
2822 | status += MXL_ControlWrite(fe, DAC_DIN_B, 0); | ||
2823 | status += MXL_SetGPIO(fe, 3, 1); | ||
2824 | status += MXL_SetGPIO(fe, 1, 0); | ||
2825 | status += MXL_SetGPIO(fe, 4, 1); | ||
2826 | } | ||
2827 | if (state->RF_IN >= 280000000 && state->RF_IN < 360000000) { | ||
2828 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); | ||
2829 | status += MXL_ControlWrite(fe, DAC_DIN_B, 0); | ||
2830 | status += MXL_SetGPIO(fe, 3, 1); | ||
2831 | status += MXL_SetGPIO(fe, 1, 0); | ||
2832 | status += MXL_SetGPIO(fe, 4, 0); | ||
2833 | } | ||
2834 | if (state->RF_IN >= 360000000 && state->RF_IN < 560000000) { | ||
2835 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); | ||
2836 | status += MXL_ControlWrite(fe, DAC_DIN_B, 0); | ||
2837 | status += MXL_SetGPIO(fe, 3, 1); | ||
2838 | status += MXL_SetGPIO(fe, 1, 1); | ||
2839 | status += MXL_SetGPIO(fe, 4, 0); | ||
2840 | } | ||
2841 | if (state->RF_IN >= 560000000 && state->RF_IN < 580000000) { | ||
2842 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); | ||
2843 | status += MXL_ControlWrite(fe, DAC_DIN_B, 29); | ||
2844 | status += MXL_SetGPIO(fe, 3, 1); | ||
2845 | status += MXL_SetGPIO(fe, 1, 1); | ||
2846 | status += MXL_SetGPIO(fe, 4, 0); | ||
2847 | } | ||
2848 | if (state->RF_IN >= 580000000 && state->RF_IN < 630000000) { | ||
2849 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); | ||
2850 | status += MXL_ControlWrite(fe, DAC_DIN_B, 0); | ||
2851 | status += MXL_SetGPIO(fe, 3, 1); | ||
2852 | status += MXL_SetGPIO(fe, 1, 1); | ||
2853 | status += MXL_SetGPIO(fe, 4, 0); | ||
2854 | } | ||
2855 | if (state->RF_IN >= 630000000 && state->RF_IN < 700000000) { | ||
2856 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); | ||
2857 | status += MXL_ControlWrite(fe, DAC_DIN_B, 16); | ||
2858 | status += MXL_SetGPIO(fe, 3, 1); | ||
2859 | status += MXL_SetGPIO(fe, 1, 1); | ||
2860 | status += MXL_SetGPIO(fe, 4, 1); | ||
2861 | } | ||
2862 | if (state->RF_IN >= 700000000 && state->RF_IN < 760000000) { | ||
2863 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); | ||
2864 | status += MXL_ControlWrite(fe, DAC_DIN_B, 7); | ||
2865 | status += MXL_SetGPIO(fe, 3, 1); | ||
2866 | status += MXL_SetGPIO(fe, 1, 1); | ||
2867 | status += MXL_SetGPIO(fe, 4, 1); | ||
2868 | } | ||
2869 | if (state->RF_IN >= 760000000 && state->RF_IN <= 900000000) { | ||
2870 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); | ||
2871 | status += MXL_ControlWrite(fe, DAC_DIN_B, 0); | ||
2872 | status += MXL_SetGPIO(fe, 3, 1); | ||
2873 | status += MXL_SetGPIO(fe, 1, 1); | ||
2874 | status += MXL_SetGPIO(fe, 4, 1); | ||
2875 | } | ||
2876 | } | ||
2877 | |||
2878 | if (state->TF_Type == MXL_TF_C_H) { | ||
2879 | |||
2880 | /* Tracking Filter type C-H for Hauppauge only */ | ||
2881 | status += MXL_ControlWrite(fe, DAC_DIN_A, 0); | ||
2882 | |||
2883 | if (state->RF_IN >= 43000000 && state->RF_IN < 150000000) { | ||
2884 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); | ||
2885 | status += MXL_SetGPIO(fe, 4, 0); | ||
2886 | status += MXL_SetGPIO(fe, 3, 1); | ||
2887 | status += MXL_SetGPIO(fe, 1, 1); | ||
2888 | } | ||
2889 | if (state->RF_IN >= 150000000 && state->RF_IN < 280000000) { | ||
2890 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); | ||
2891 | status += MXL_SetGPIO(fe, 4, 1); | ||
2892 | status += MXL_SetGPIO(fe, 3, 0); | ||
2893 | status += MXL_SetGPIO(fe, 1, 1); | ||
2894 | } | ||
2895 | if (state->RF_IN >= 280000000 && state->RF_IN < 360000000) { | ||
2896 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); | ||
2897 | status += MXL_SetGPIO(fe, 4, 1); | ||
2898 | status += MXL_SetGPIO(fe, 3, 0); | ||
2899 | status += MXL_SetGPIO(fe, 1, 0); | ||
2900 | } | ||
2901 | if (state->RF_IN >= 360000000 && state->RF_IN < 560000000) { | ||
2902 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); | ||
2903 | status += MXL_SetGPIO(fe, 4, 1); | ||
2904 | status += MXL_SetGPIO(fe, 3, 1); | ||
2905 | status += MXL_SetGPIO(fe, 1, 0); | ||
2906 | } | ||
2907 | if (state->RF_IN >= 560000000 && state->RF_IN < 580000000) { | ||
2908 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); | ||
2909 | status += MXL_SetGPIO(fe, 4, 1); | ||
2910 | status += MXL_SetGPIO(fe, 3, 1); | ||
2911 | status += MXL_SetGPIO(fe, 1, 0); | ||
2912 | } | ||
2913 | if (state->RF_IN >= 580000000 && state->RF_IN < 630000000) { | ||
2914 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); | ||
2915 | status += MXL_SetGPIO(fe, 4, 1); | ||
2916 | status += MXL_SetGPIO(fe, 3, 1); | ||
2917 | status += MXL_SetGPIO(fe, 1, 0); | ||
2918 | } | ||
2919 | if (state->RF_IN >= 630000000 && state->RF_IN < 700000000) { | ||
2920 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); | ||
2921 | status += MXL_SetGPIO(fe, 4, 1); | ||
2922 | status += MXL_SetGPIO(fe, 3, 1); | ||
2923 | status += MXL_SetGPIO(fe, 1, 1); | ||
2924 | } | ||
2925 | if (state->RF_IN >= 700000000 && state->RF_IN < 760000000) { | ||
2926 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); | ||
2927 | status += MXL_SetGPIO(fe, 4, 1); | ||
2928 | status += MXL_SetGPIO(fe, 3, 1); | ||
2929 | status += MXL_SetGPIO(fe, 1, 1); | ||
2930 | } | ||
2931 | if (state->RF_IN >= 760000000 && state->RF_IN <= 900000000) { | ||
2932 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); | ||
2933 | status += MXL_SetGPIO(fe, 4, 1); | ||
2934 | status += MXL_SetGPIO(fe, 3, 1); | ||
2935 | status += MXL_SetGPIO(fe, 1, 1); | ||
2936 | } | ||
2937 | } | ||
2938 | |||
2939 | if (state->TF_Type == MXL_TF_D) { /* Tracking Filter type D */ | ||
2940 | |||
2941 | status += MXL_ControlWrite(fe, DAC_DIN_B, 0); | ||
2942 | |||
2943 | if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) { | ||
2944 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
2945 | status += MXL_SetGPIO(fe, 4, 0); | ||
2946 | status += MXL_SetGPIO(fe, 1, 1); | ||
2947 | status += MXL_SetGPIO(fe, 3, 1); | ||
2948 | } | ||
2949 | if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) { | ||
2950 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
2951 | status += MXL_SetGPIO(fe, 4, 0); | ||
2952 | status += MXL_SetGPIO(fe, 1, 0); | ||
2953 | status += MXL_SetGPIO(fe, 3, 1); | ||
2954 | } | ||
2955 | if (state->RF_IN >= 250000000 && state->RF_IN < 310000000) { | ||
2956 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
2957 | status += MXL_SetGPIO(fe, 4, 1); | ||
2958 | status += MXL_SetGPIO(fe, 1, 0); | ||
2959 | status += MXL_SetGPIO(fe, 3, 1); | ||
2960 | } | ||
2961 | if (state->RF_IN >= 310000000 && state->RF_IN < 360000000) { | ||
2962 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
2963 | status += MXL_SetGPIO(fe, 4, 1); | ||
2964 | status += MXL_SetGPIO(fe, 1, 0); | ||
2965 | status += MXL_SetGPIO(fe, 3, 0); | ||
2966 | } | ||
2967 | if (state->RF_IN >= 360000000 && state->RF_IN < 470000000) { | ||
2968 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
2969 | status += MXL_SetGPIO(fe, 4, 1); | ||
2970 | status += MXL_SetGPIO(fe, 1, 1); | ||
2971 | status += MXL_SetGPIO(fe, 3, 0); | ||
2972 | } | ||
2973 | if (state->RF_IN >= 470000000 && state->RF_IN < 640000000) { | ||
2974 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); | ||
2975 | status += MXL_SetGPIO(fe, 4, 1); | ||
2976 | status += MXL_SetGPIO(fe, 1, 1); | ||
2977 | status += MXL_SetGPIO(fe, 3, 0); | ||
2978 | } | ||
2979 | if (state->RF_IN >= 640000000 && state->RF_IN <= 900000000) { | ||
2980 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); | ||
2981 | status += MXL_SetGPIO(fe, 4, 1); | ||
2982 | status += MXL_SetGPIO(fe, 1, 1); | ||
2983 | status += MXL_SetGPIO(fe, 3, 1); | ||
2984 | } | ||
2985 | } | ||
2986 | |||
2987 | if (state->TF_Type == MXL_TF_D_L) { | ||
2988 | |||
2989 | /* Tracking Filter type D-L for Lumanate ONLY change 2.6.3 */ | ||
2990 | status += MXL_ControlWrite(fe, DAC_DIN_A, 0); | ||
2991 | |||
2992 | /* if UHF and terrestrial => Turn off Tracking Filter */ | ||
2993 | if (state->RF_IN >= 471000000 && | ||
2994 | (state->RF_IN - 471000000)%6000000 != 0) { | ||
2995 | /* Turn off all the banks */ | ||
2996 | status += MXL_SetGPIO(fe, 3, 1); | ||
2997 | status += MXL_SetGPIO(fe, 1, 1); | ||
2998 | status += MXL_SetGPIO(fe, 4, 1); | ||
2999 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); | ||
3000 | status += MXL_ControlWrite(fe, AGC_IF, 10); | ||
3001 | } else { | ||
3002 | /* if VHF or cable => Turn on Tracking Filter */ | ||
3003 | if (state->RF_IN >= 43000000 && | ||
3004 | state->RF_IN < 140000000) { | ||
3005 | |||
3006 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); | ||
3007 | status += MXL_SetGPIO(fe, 4, 1); | ||
3008 | status += MXL_SetGPIO(fe, 1, 1); | ||
3009 | status += MXL_SetGPIO(fe, 3, 0); | ||
3010 | } | ||
3011 | if (state->RF_IN >= 140000000 && | ||
3012 | state->RF_IN < 240000000) { | ||
3013 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); | ||
3014 | status += MXL_SetGPIO(fe, 4, 1); | ||
3015 | status += MXL_SetGPIO(fe, 1, 0); | ||
3016 | status += MXL_SetGPIO(fe, 3, 0); | ||
3017 | } | ||
3018 | if (state->RF_IN >= 240000000 && | ||
3019 | state->RF_IN < 340000000) { | ||
3020 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); | ||
3021 | status += MXL_SetGPIO(fe, 4, 0); | ||
3022 | status += MXL_SetGPIO(fe, 1, 1); | ||
3023 | status += MXL_SetGPIO(fe, 3, 0); | ||
3024 | } | ||
3025 | if (state->RF_IN >= 340000000 && | ||
3026 | state->RF_IN < 430000000) { | ||
3027 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); | ||
3028 | status += MXL_SetGPIO(fe, 4, 0); | ||
3029 | status += MXL_SetGPIO(fe, 1, 0); | ||
3030 | status += MXL_SetGPIO(fe, 3, 1); | ||
3031 | } | ||
3032 | if (state->RF_IN >= 430000000 && | ||
3033 | state->RF_IN < 470000000) { | ||
3034 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); | ||
3035 | status += MXL_SetGPIO(fe, 4, 1); | ||
3036 | status += MXL_SetGPIO(fe, 1, 0); | ||
3037 | status += MXL_SetGPIO(fe, 3, 1); | ||
3038 | } | ||
3039 | if (state->RF_IN >= 470000000 && | ||
3040 | state->RF_IN < 570000000) { | ||
3041 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); | ||
3042 | status += MXL_SetGPIO(fe, 4, 0); | ||
3043 | status += MXL_SetGPIO(fe, 1, 0); | ||
3044 | status += MXL_SetGPIO(fe, 3, 1); | ||
3045 | } | ||
3046 | if (state->RF_IN >= 570000000 && | ||
3047 | state->RF_IN < 620000000) { | ||
3048 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 0); | ||
3049 | status += MXL_SetGPIO(fe, 4, 0); | ||
3050 | status += MXL_SetGPIO(fe, 1, 1); | ||
3051 | status += MXL_SetGPIO(fe, 3, 1); | ||
3052 | } | ||
3053 | if (state->RF_IN >= 620000000 && | ||
3054 | state->RF_IN < 760000000) { | ||
3055 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); | ||
3056 | status += MXL_SetGPIO(fe, 4, 0); | ||
3057 | status += MXL_SetGPIO(fe, 1, 1); | ||
3058 | status += MXL_SetGPIO(fe, 3, 1); | ||
3059 | } | ||
3060 | if (state->RF_IN >= 760000000 && | ||
3061 | state->RF_IN <= 900000000) { | ||
3062 | status += MXL_ControlWrite(fe, DAC_A_ENABLE, 1); | ||
3063 | status += MXL_SetGPIO(fe, 4, 1); | ||
3064 | status += MXL_SetGPIO(fe, 1, 1); | ||
3065 | status += MXL_SetGPIO(fe, 3, 1); | ||
3066 | } | ||
3067 | } | ||
3068 | } | ||
3069 | |||
3070 | if (state->TF_Type == MXL_TF_E) /* Tracking Filter type E */ { | ||
3071 | |||
3072 | status += MXL_ControlWrite(fe, DAC_DIN_B, 0); | ||
3073 | |||
3074 | if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) { | ||
3075 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
3076 | status += MXL_SetGPIO(fe, 4, 0); | ||
3077 | status += MXL_SetGPIO(fe, 1, 1); | ||
3078 | status += MXL_SetGPIO(fe, 3, 1); | ||
3079 | } | ||
3080 | if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) { | ||
3081 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
3082 | status += MXL_SetGPIO(fe, 4, 0); | ||
3083 | status += MXL_SetGPIO(fe, 1, 0); | ||
3084 | status += MXL_SetGPIO(fe, 3, 1); | ||
3085 | } | ||
3086 | if (state->RF_IN >= 250000000 && state->RF_IN < 310000000) { | ||
3087 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
3088 | status += MXL_SetGPIO(fe, 4, 1); | ||
3089 | status += MXL_SetGPIO(fe, 1, 0); | ||
3090 | status += MXL_SetGPIO(fe, 3, 1); | ||
3091 | } | ||
3092 | if (state->RF_IN >= 310000000 && state->RF_IN < 360000000) { | ||
3093 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
3094 | status += MXL_SetGPIO(fe, 4, 1); | ||
3095 | status += MXL_SetGPIO(fe, 1, 0); | ||
3096 | status += MXL_SetGPIO(fe, 3, 0); | ||
3097 | } | ||
3098 | if (state->RF_IN >= 360000000 && state->RF_IN < 470000000) { | ||
3099 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
3100 | status += MXL_SetGPIO(fe, 4, 1); | ||
3101 | status += MXL_SetGPIO(fe, 1, 1); | ||
3102 | status += MXL_SetGPIO(fe, 3, 0); | ||
3103 | } | ||
3104 | if (state->RF_IN >= 470000000 && state->RF_IN < 640000000) { | ||
3105 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); | ||
3106 | status += MXL_SetGPIO(fe, 4, 1); | ||
3107 | status += MXL_SetGPIO(fe, 1, 1); | ||
3108 | status += MXL_SetGPIO(fe, 3, 0); | ||
3109 | } | ||
3110 | if (state->RF_IN >= 640000000 && state->RF_IN <= 900000000) { | ||
3111 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); | ||
3112 | status += MXL_SetGPIO(fe, 4, 1); | ||
3113 | status += MXL_SetGPIO(fe, 1, 1); | ||
3114 | status += MXL_SetGPIO(fe, 3, 1); | ||
3115 | } | ||
3116 | } | ||
3117 | |||
3118 | if (state->TF_Type == MXL_TF_F) { | ||
3119 | |||
3120 | /* Tracking Filter type F */ | ||
3121 | status += MXL_ControlWrite(fe, DAC_DIN_B, 0); | ||
3122 | |||
3123 | if (state->RF_IN >= 43000000 && state->RF_IN < 160000000) { | ||
3124 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
3125 | status += MXL_SetGPIO(fe, 4, 0); | ||
3126 | status += MXL_SetGPIO(fe, 1, 1); | ||
3127 | status += MXL_SetGPIO(fe, 3, 1); | ||
3128 | } | ||
3129 | if (state->RF_IN >= 160000000 && state->RF_IN < 210000000) { | ||
3130 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
3131 | status += MXL_SetGPIO(fe, 4, 0); | ||
3132 | status += MXL_SetGPIO(fe, 1, 0); | ||
3133 | status += MXL_SetGPIO(fe, 3, 1); | ||
3134 | } | ||
3135 | if (state->RF_IN >= 210000000 && state->RF_IN < 300000000) { | ||
3136 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
3137 | status += MXL_SetGPIO(fe, 4, 1); | ||
3138 | status += MXL_SetGPIO(fe, 1, 0); | ||
3139 | status += MXL_SetGPIO(fe, 3, 1); | ||
3140 | } | ||
3141 | if (state->RF_IN >= 300000000 && state->RF_IN < 390000000) { | ||
3142 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
3143 | status += MXL_SetGPIO(fe, 4, 1); | ||
3144 | status += MXL_SetGPIO(fe, 1, 0); | ||
3145 | status += MXL_SetGPIO(fe, 3, 0); | ||
3146 | } | ||
3147 | if (state->RF_IN >= 390000000 && state->RF_IN < 515000000) { | ||
3148 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
3149 | status += MXL_SetGPIO(fe, 4, 1); | ||
3150 | status += MXL_SetGPIO(fe, 1, 1); | ||
3151 | status += MXL_SetGPIO(fe, 3, 0); | ||
3152 | } | ||
3153 | if (state->RF_IN >= 515000000 && state->RF_IN < 650000000) { | ||
3154 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); | ||
3155 | status += MXL_SetGPIO(fe, 4, 1); | ||
3156 | status += MXL_SetGPIO(fe, 1, 1); | ||
3157 | status += MXL_SetGPIO(fe, 3, 0); | ||
3158 | } | ||
3159 | if (state->RF_IN >= 650000000 && state->RF_IN <= 900000000) { | ||
3160 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); | ||
3161 | status += MXL_SetGPIO(fe, 4, 1); | ||
3162 | status += MXL_SetGPIO(fe, 1, 1); | ||
3163 | status += MXL_SetGPIO(fe, 3, 1); | ||
3164 | } | ||
3165 | } | ||
3166 | |||
3167 | if (state->TF_Type == MXL_TF_E_2) { | ||
3168 | |||
3169 | /* Tracking Filter type E_2 */ | ||
3170 | status += MXL_ControlWrite(fe, DAC_DIN_B, 0); | ||
3171 | |||
3172 | if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) { | ||
3173 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
3174 | status += MXL_SetGPIO(fe, 4, 0); | ||
3175 | status += MXL_SetGPIO(fe, 1, 1); | ||
3176 | status += MXL_SetGPIO(fe, 3, 1); | ||
3177 | } | ||
3178 | if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) { | ||
3179 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
3180 | status += MXL_SetGPIO(fe, 4, 0); | ||
3181 | status += MXL_SetGPIO(fe, 1, 0); | ||
3182 | status += MXL_SetGPIO(fe, 3, 1); | ||
3183 | } | ||
3184 | if (state->RF_IN >= 250000000 && state->RF_IN < 350000000) { | ||
3185 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
3186 | status += MXL_SetGPIO(fe, 4, 1); | ||
3187 | status += MXL_SetGPIO(fe, 1, 0); | ||
3188 | status += MXL_SetGPIO(fe, 3, 1); | ||
3189 | } | ||
3190 | if (state->RF_IN >= 350000000 && state->RF_IN < 400000000) { | ||
3191 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
3192 | status += MXL_SetGPIO(fe, 4, 1); | ||
3193 | status += MXL_SetGPIO(fe, 1, 0); | ||
3194 | status += MXL_SetGPIO(fe, 3, 0); | ||
3195 | } | ||
3196 | if (state->RF_IN >= 400000000 && state->RF_IN < 570000000) { | ||
3197 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
3198 | status += MXL_SetGPIO(fe, 4, 1); | ||
3199 | status += MXL_SetGPIO(fe, 1, 1); | ||
3200 | status += MXL_SetGPIO(fe, 3, 0); | ||
3201 | } | ||
3202 | if (state->RF_IN >= 570000000 && state->RF_IN < 770000000) { | ||
3203 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); | ||
3204 | status += MXL_SetGPIO(fe, 4, 1); | ||
3205 | status += MXL_SetGPIO(fe, 1, 1); | ||
3206 | status += MXL_SetGPIO(fe, 3, 0); | ||
3207 | } | ||
3208 | if (state->RF_IN >= 770000000 && state->RF_IN <= 900000000) { | ||
3209 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); | ||
3210 | status += MXL_SetGPIO(fe, 4, 1); | ||
3211 | status += MXL_SetGPIO(fe, 1, 1); | ||
3212 | status += MXL_SetGPIO(fe, 3, 1); | ||
3213 | } | ||
3214 | } | ||
3215 | |||
3216 | if (state->TF_Type == MXL_TF_G) { | ||
3217 | |||
3218 | /* Tracking Filter type G add for v2.6.8 */ | ||
3219 | status += MXL_ControlWrite(fe, DAC_DIN_B, 0); | ||
3220 | |||
3221 | if (state->RF_IN >= 50000000 && state->RF_IN < 190000000) { | ||
3222 | |||
3223 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
3224 | status += MXL_SetGPIO(fe, 4, 0); | ||
3225 | status += MXL_SetGPIO(fe, 1, 1); | ||
3226 | status += MXL_SetGPIO(fe, 3, 1); | ||
3227 | } | ||
3228 | if (state->RF_IN >= 190000000 && state->RF_IN < 280000000) { | ||
3229 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
3230 | status += MXL_SetGPIO(fe, 4, 0); | ||
3231 | status += MXL_SetGPIO(fe, 1, 0); | ||
3232 | status += MXL_SetGPIO(fe, 3, 1); | ||
3233 | } | ||
3234 | if (state->RF_IN >= 280000000 && state->RF_IN < 350000000) { | ||
3235 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
3236 | status += MXL_SetGPIO(fe, 4, 1); | ||
3237 | status += MXL_SetGPIO(fe, 1, 0); | ||
3238 | status += MXL_SetGPIO(fe, 3, 1); | ||
3239 | } | ||
3240 | if (state->RF_IN >= 350000000 && state->RF_IN < 400000000) { | ||
3241 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
3242 | status += MXL_SetGPIO(fe, 4, 1); | ||
3243 | status += MXL_SetGPIO(fe, 1, 0); | ||
3244 | status += MXL_SetGPIO(fe, 3, 0); | ||
3245 | } | ||
3246 | if (state->RF_IN >= 400000000 && state->RF_IN < 470000000) { | ||
3247 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); | ||
3248 | status += MXL_SetGPIO(fe, 4, 1); | ||
3249 | status += MXL_SetGPIO(fe, 1, 0); | ||
3250 | status += MXL_SetGPIO(fe, 3, 1); | ||
3251 | } | ||
3252 | if (state->RF_IN >= 470000000 && state->RF_IN < 640000000) { | ||
3253 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
3254 | status += MXL_SetGPIO(fe, 4, 1); | ||
3255 | status += MXL_SetGPIO(fe, 1, 1); | ||
3256 | status += MXL_SetGPIO(fe, 3, 0); | ||
3257 | } | ||
3258 | if (state->RF_IN >= 640000000 && state->RF_IN < 820000000) { | ||
3259 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); | ||
3260 | status += MXL_SetGPIO(fe, 4, 1); | ||
3261 | status += MXL_SetGPIO(fe, 1, 1); | ||
3262 | status += MXL_SetGPIO(fe, 3, 0); | ||
3263 | } | ||
3264 | if (state->RF_IN >= 820000000 && state->RF_IN <= 900000000) { | ||
3265 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); | ||
3266 | status += MXL_SetGPIO(fe, 4, 1); | ||
3267 | status += MXL_SetGPIO(fe, 1, 1); | ||
3268 | status += MXL_SetGPIO(fe, 3, 1); | ||
3269 | } | ||
3270 | } | ||
3271 | |||
3272 | if (state->TF_Type == MXL_TF_E_NA) { | ||
3273 | |||
3274 | /* Tracking Filter type E-NA for Empia ONLY change for 2.6.8 */ | ||
3275 | status += MXL_ControlWrite(fe, DAC_DIN_B, 0); | ||
3276 | |||
3277 | /* if UHF and terrestrial=> Turn off Tracking Filter */ | ||
3278 | if (state->RF_IN >= 471000000 && | ||
3279 | (state->RF_IN - 471000000)%6000000 != 0) { | ||
3280 | |||
3281 | /* Turn off all the banks */ | ||
3282 | status += MXL_SetGPIO(fe, 3, 1); | ||
3283 | status += MXL_SetGPIO(fe, 1, 1); | ||
3284 | status += MXL_SetGPIO(fe, 4, 1); | ||
3285 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
3286 | |||
3287 | /* 2.6.12 Turn on RSSI */ | ||
3288 | status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1); | ||
3289 | status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1); | ||
3290 | status += MXL_ControlWrite(fe, AGC_EN_RSSI, 1); | ||
3291 | status += MXL_ControlWrite(fe, RFA_ENCLKRFAGC, 1); | ||
3292 | |||
3293 | /* RSSI reference point */ | ||
3294 | status += MXL_ControlWrite(fe, RFA_RSSI_REFH, 5); | ||
3295 | status += MXL_ControlWrite(fe, RFA_RSSI_REF, 3); | ||
3296 | status += MXL_ControlWrite(fe, RFA_RSSI_REFL, 2); | ||
3297 | |||
3298 | /* following parameter is from analog OTA mode, | ||
3299 | * can be change to seek better performance */ | ||
3300 | status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 3); | ||
3301 | } else { | ||
3302 | /* if VHF or Cable => Turn on Tracking Filter */ | ||
3303 | |||
3304 | /* 2.6.12 Turn off RSSI */ | ||
3305 | status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0); | ||
3306 | |||
3307 | /* change back from above condition */ | ||
3308 | status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 5); | ||
3309 | |||
3310 | |||
3311 | if (state->RF_IN >= 43000000 && state->RF_IN < 174000000) { | ||
3312 | |||
3313 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
3314 | status += MXL_SetGPIO(fe, 4, 0); | ||
3315 | status += MXL_SetGPIO(fe, 1, 1); | ||
3316 | status += MXL_SetGPIO(fe, 3, 1); | ||
3317 | } | ||
3318 | if (state->RF_IN >= 174000000 && state->RF_IN < 250000000) { | ||
3319 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
3320 | status += MXL_SetGPIO(fe, 4, 0); | ||
3321 | status += MXL_SetGPIO(fe, 1, 0); | ||
3322 | status += MXL_SetGPIO(fe, 3, 1); | ||
3323 | } | ||
3324 | if (state->RF_IN >= 250000000 && state->RF_IN < 350000000) { | ||
3325 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
3326 | status += MXL_SetGPIO(fe, 4, 1); | ||
3327 | status += MXL_SetGPIO(fe, 1, 0); | ||
3328 | status += MXL_SetGPIO(fe, 3, 1); | ||
3329 | } | ||
3330 | if (state->RF_IN >= 350000000 && state->RF_IN < 400000000) { | ||
3331 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
3332 | status += MXL_SetGPIO(fe, 4, 1); | ||
3333 | status += MXL_SetGPIO(fe, 1, 0); | ||
3334 | status += MXL_SetGPIO(fe, 3, 0); | ||
3335 | } | ||
3336 | if (state->RF_IN >= 400000000 && state->RF_IN < 570000000) { | ||
3337 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 0); | ||
3338 | status += MXL_SetGPIO(fe, 4, 1); | ||
3339 | status += MXL_SetGPIO(fe, 1, 1); | ||
3340 | status += MXL_SetGPIO(fe, 3, 0); | ||
3341 | } | ||
3342 | if (state->RF_IN >= 570000000 && state->RF_IN < 770000000) { | ||
3343 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); | ||
3344 | status += MXL_SetGPIO(fe, 4, 1); | ||
3345 | status += MXL_SetGPIO(fe, 1, 1); | ||
3346 | status += MXL_SetGPIO(fe, 3, 0); | ||
3347 | } | ||
3348 | if (state->RF_IN >= 770000000 && state->RF_IN <= 900000000) { | ||
3349 | status += MXL_ControlWrite(fe, DAC_B_ENABLE, 1); | ||
3350 | status += MXL_SetGPIO(fe, 4, 1); | ||
3351 | status += MXL_SetGPIO(fe, 1, 1); | ||
3352 | status += MXL_SetGPIO(fe, 3, 1); | ||
3353 | } | ||
3354 | } | ||
3355 | } | ||
3356 | return status ; | ||
3357 | } | ||
3358 | |||
3359 | static u16 MXL_SetGPIO(struct dvb_frontend *fe, u8 GPIO_Num, u8 GPIO_Val) | ||
3360 | { | ||
3361 | u16 status = 0; | ||
3362 | |||
3363 | if (GPIO_Num == 1) | ||
3364 | status += MXL_ControlWrite(fe, GPIO_1B, GPIO_Val ? 0 : 1); | ||
3365 | |||
3366 | /* GPIO2 is not available */ | ||
3367 | |||
3368 | if (GPIO_Num == 3) { | ||
3369 | if (GPIO_Val == 1) { | ||
3370 | status += MXL_ControlWrite(fe, GPIO_3, 0); | ||
3371 | status += MXL_ControlWrite(fe, GPIO_3B, 0); | ||
3372 | } | ||
3373 | if (GPIO_Val == 0) { | ||
3374 | status += MXL_ControlWrite(fe, GPIO_3, 1); | ||
3375 | status += MXL_ControlWrite(fe, GPIO_3B, 1); | ||
3376 | } | ||
3377 | if (GPIO_Val == 3) { /* tri-state */ | ||
3378 | status += MXL_ControlWrite(fe, GPIO_3, 0); | ||
3379 | status += MXL_ControlWrite(fe, GPIO_3B, 1); | ||
3380 | } | ||
3381 | } | ||
3382 | if (GPIO_Num == 4) { | ||
3383 | if (GPIO_Val == 1) { | ||
3384 | status += MXL_ControlWrite(fe, GPIO_4, 0); | ||
3385 | status += MXL_ControlWrite(fe, GPIO_4B, 0); | ||
3386 | } | ||
3387 | if (GPIO_Val == 0) { | ||
3388 | status += MXL_ControlWrite(fe, GPIO_4, 1); | ||
3389 | status += MXL_ControlWrite(fe, GPIO_4B, 1); | ||
3390 | } | ||
3391 | if (GPIO_Val == 3) { /* tri-state */ | ||
3392 | status += MXL_ControlWrite(fe, GPIO_4, 0); | ||
3393 | status += MXL_ControlWrite(fe, GPIO_4B, 1); | ||
3394 | } | ||
3395 | } | ||
3396 | |||
3397 | return status; | ||
3398 | } | ||
3399 | |||
3400 | static u16 MXL_ControlWrite(struct dvb_frontend *fe, u16 ControlNum, u32 value) | ||
3401 | { | ||
3402 | u16 status = 0; | ||
3403 | |||
3404 | /* Will write ALL Matching Control Name */ | ||
3405 | /* Write Matching INIT Control */ | ||
3406 | status += MXL_ControlWrite_Group(fe, ControlNum, value, 1); | ||
3407 | /* Write Matching CH Control */ | ||
3408 | status += MXL_ControlWrite_Group(fe, ControlNum, value, 2); | ||
3409 | #ifdef _MXL_INTERNAL | ||
3410 | /* Write Matching MXL Control */ | ||
3411 | status += MXL_ControlWrite_Group(fe, ControlNum, value, 3); | ||
3412 | #endif | ||
3413 | return status; | ||
3414 | } | ||
3415 | |||
3416 | static u16 MXL_ControlWrite_Group(struct dvb_frontend *fe, u16 controlNum, | ||
3417 | u32 value, u16 controlGroup) | ||
3418 | { | ||
3419 | struct mxl5005s_state *state = fe->tuner_priv; | ||
3420 | u16 i, j, k; | ||
3421 | u32 highLimit; | ||
3422 | u32 ctrlVal; | ||
3423 | |||
3424 | if (controlGroup == 1) /* Initial Control */ { | ||
3425 | |||
3426 | for (i = 0; i < state->Init_Ctrl_Num; i++) { | ||
3427 | |||
3428 | if (controlNum == state->Init_Ctrl[i].Ctrl_Num) { | ||
3429 | |||
3430 | highLimit = 1 << state->Init_Ctrl[i].size; | ||
3431 | if (value < highLimit) { | ||
3432 | for (j = 0; j < state->Init_Ctrl[i].size; j++) { | ||
3433 | state->Init_Ctrl[i].val[j] = (u8)((value >> j) & 0x01); | ||
3434 | MXL_RegWriteBit(fe, (u8)(state->Init_Ctrl[i].addr[j]), | ||
3435 | (u8)(state->Init_Ctrl[i].bit[j]), | ||
3436 | (u8)((value>>j) & 0x01)); | ||
3437 | } | ||
3438 | ctrlVal = 0; | ||
3439 | for (k = 0; k < state->Init_Ctrl[i].size; k++) | ||
3440 | ctrlVal += state->Init_Ctrl[i].val[k] * (1 << k); | ||
3441 | } else | ||
3442 | return -1; | ||
3443 | } | ||
3444 | } | ||
3445 | } | ||
3446 | if (controlGroup == 2) /* Chan change Control */ { | ||
3447 | |||
3448 | for (i = 0; i < state->CH_Ctrl_Num; i++) { | ||
3449 | |||
3450 | if (controlNum == state->CH_Ctrl[i].Ctrl_Num) { | ||
3451 | |||
3452 | highLimit = 1 << state->CH_Ctrl[i].size; | ||
3453 | if (value < highLimit) { | ||
3454 | for (j = 0; j < state->CH_Ctrl[i].size; j++) { | ||
3455 | state->CH_Ctrl[i].val[j] = (u8)((value >> j) & 0x01); | ||
3456 | MXL_RegWriteBit(fe, (u8)(state->CH_Ctrl[i].addr[j]), | ||
3457 | (u8)(state->CH_Ctrl[i].bit[j]), | ||
3458 | (u8)((value>>j) & 0x01)); | ||
3459 | } | ||
3460 | ctrlVal = 0; | ||
3461 | for (k = 0; k < state->CH_Ctrl[i].size; k++) | ||
3462 | ctrlVal += state->CH_Ctrl[i].val[k] * (1 << k); | ||
3463 | } else | ||
3464 | return -1; | ||
3465 | } | ||
3466 | } | ||
3467 | } | ||
3468 | #ifdef _MXL_INTERNAL | ||
3469 | if (controlGroup == 3) /* Maxlinear Control */ { | ||
3470 | |||
3471 | for (i = 0; i < state->MXL_Ctrl_Num; i++) { | ||
3472 | |||
3473 | if (controlNum == state->MXL_Ctrl[i].Ctrl_Num) { | ||
3474 | |||
3475 | highLimit = (1 << state->MXL_Ctrl[i].size); | ||
3476 | if (value < highLimit) { | ||
3477 | for (j = 0; j < state->MXL_Ctrl[i].size; j++) { | ||
3478 | state->MXL_Ctrl[i].val[j] = (u8)((value >> j) & 0x01); | ||
3479 | MXL_RegWriteBit(fe, (u8)(state->MXL_Ctrl[i].addr[j]), | ||
3480 | (u8)(state->MXL_Ctrl[i].bit[j]), | ||
3481 | (u8)((value>>j) & 0x01)); | ||
3482 | } | ||
3483 | ctrlVal = 0; | ||
3484 | for (k = 0; k < state->MXL_Ctrl[i].size; k++) | ||
3485 | ctrlVal += state-> | ||
3486 | MXL_Ctrl[i].val[k] * | ||
3487 | (1 << k); | ||
3488 | } else | ||
3489 | return -1; | ||
3490 | } | ||
3491 | } | ||
3492 | } | ||
3493 | #endif | ||
3494 | return 0 ; /* successful return */ | ||
3495 | } | ||
3496 | |||
3497 | static u16 MXL_RegRead(struct dvb_frontend *fe, u8 RegNum, u8 *RegVal) | ||
3498 | { | ||
3499 | struct mxl5005s_state *state = fe->tuner_priv; | ||
3500 | int i ; | ||
3501 | |||
3502 | for (i = 0; i < 104; i++) { | ||
3503 | if (RegNum == state->TunerRegs[i].Reg_Num) { | ||
3504 | *RegVal = (u8)(state->TunerRegs[i].Reg_Val); | ||
3505 | return 0; | ||
3506 | } | ||
3507 | } | ||
3508 | |||
3509 | return 1; | ||
3510 | } | ||
3511 | |||
3512 | static u16 MXL_ControlRead(struct dvb_frontend *fe, u16 controlNum, u32 *value) | ||
3513 | { | ||
3514 | struct mxl5005s_state *state = fe->tuner_priv; | ||
3515 | u32 ctrlVal ; | ||
3516 | u16 i, k ; | ||
3517 | |||
3518 | for (i = 0; i < state->Init_Ctrl_Num ; i++) { | ||
3519 | |||
3520 | if (controlNum == state->Init_Ctrl[i].Ctrl_Num) { | ||
3521 | |||
3522 | ctrlVal = 0; | ||
3523 | for (k = 0; k < state->Init_Ctrl[i].size; k++) | ||
3524 | ctrlVal += state->Init_Ctrl[i].val[k] * (1<<k); | ||
3525 | *value = ctrlVal; | ||
3526 | return 0; | ||
3527 | } | ||
3528 | } | ||
3529 | |||
3530 | for (i = 0; i < state->CH_Ctrl_Num ; i++) { | ||
3531 | |||
3532 | if (controlNum == state->CH_Ctrl[i].Ctrl_Num) { | ||
3533 | |||
3534 | ctrlVal = 0; | ||
3535 | for (k = 0; k < state->CH_Ctrl[i].size; k++) | ||
3536 | ctrlVal += state->CH_Ctrl[i].val[k] * (1 << k); | ||
3537 | *value = ctrlVal; | ||
3538 | return 0; | ||
3539 | |||
3540 | } | ||
3541 | } | ||
3542 | |||
3543 | #ifdef _MXL_INTERNAL | ||
3544 | for (i = 0; i < state->MXL_Ctrl_Num ; i++) { | ||
3545 | |||
3546 | if (controlNum == state->MXL_Ctrl[i].Ctrl_Num) { | ||
3547 | |||
3548 | ctrlVal = 0; | ||
3549 | for (k = 0; k < state->MXL_Ctrl[i].size; k++) | ||
3550 | ctrlVal += state->MXL_Ctrl[i].val[k] * (1<<k); | ||
3551 | *value = ctrlVal; | ||
3552 | return 0; | ||
3553 | |||
3554 | } | ||
3555 | } | ||
3556 | #endif | ||
3557 | return 1; | ||
3558 | } | ||
3559 | |||
3560 | static void MXL_RegWriteBit(struct dvb_frontend *fe, u8 address, u8 bit, | ||
3561 | u8 bitVal) | ||
3562 | { | ||
3563 | struct mxl5005s_state *state = fe->tuner_priv; | ||
3564 | int i ; | ||
3565 | |||
3566 | const u8 AND_MAP[8] = { | ||
3567 | 0xFE, 0xFD, 0xFB, 0xF7, | ||
3568 | 0xEF, 0xDF, 0xBF, 0x7F } ; | ||
3569 | |||
3570 | const u8 OR_MAP[8] = { | ||
3571 | 0x01, 0x02, 0x04, 0x08, | ||
3572 | 0x10, 0x20, 0x40, 0x80 } ; | ||
3573 | |||
3574 | for (i = 0; i < state->TunerRegs_Num; i++) { | ||
3575 | if (state->TunerRegs[i].Reg_Num == address) { | ||
3576 | if (bitVal) | ||
3577 | state->TunerRegs[i].Reg_Val |= OR_MAP[bit]; | ||
3578 | else | ||
3579 | state->TunerRegs[i].Reg_Val &= AND_MAP[bit]; | ||
3580 | break ; | ||
3581 | } | ||
3582 | } | ||
3583 | } | ||
3584 | |||
3585 | static u32 MXL_Ceiling(u32 value, u32 resolution) | ||
3586 | { | ||
3587 | return value / resolution + (value % resolution > 0 ? 1 : 0); | ||
3588 | } | ||
3589 | |||
3590 | /* Retrieve the Initialzation Registers */ | ||
3591 | static u16 MXL_GetInitRegister(struct dvb_frontend *fe, u8 *RegNum, | ||
3592 | u8 *RegVal, int *count) | ||
3593 | { | ||
3594 | u16 status = 0; | ||
3595 | int i ; | ||
3596 | |||
3597 | u8 RegAddr[] = { | ||
3598 | 11, 12, 13, 22, 32, 43, 44, 53, 56, 59, 73, | ||
3599 | 76, 77, 91, 134, 135, 137, 147, | ||
3600 | 156, 166, 167, 168, 25 }; | ||
3601 | |||
3602 | *count = ARRAY_SIZE(RegAddr); | ||
3603 | |||
3604 | status += MXL_BlockInit(fe); | ||
3605 | |||
3606 | for (i = 0 ; i < *count; i++) { | ||
3607 | RegNum[i] = RegAddr[i]; | ||
3608 | status += MXL_RegRead(fe, RegNum[i], &RegVal[i]); | ||
3609 | } | ||
3610 | |||
3611 | return status; | ||
3612 | } | ||
3613 | |||
3614 | static u16 MXL_GetCHRegister(struct dvb_frontend *fe, u8 *RegNum, u8 *RegVal, | ||
3615 | int *count) | ||
3616 | { | ||
3617 | u16 status = 0; | ||
3618 | int i ; | ||
3619 | |||
3620 | /* add 77, 166, 167, 168 register for 2.6.12 */ | ||
3621 | #ifdef _MXL_PRODUCTION | ||
3622 | u8 RegAddr[] = {14, 15, 16, 17, 22, 43, 65, 68, 69, 70, 73, 92, 93, 106, | ||
3623 | 107, 108, 109, 110, 111, 112, 136, 138, 149, 77, 166, 167, 168 } ; | ||
3624 | #else | ||
3625 | u8 RegAddr[] = {14, 15, 16, 17, 22, 43, 68, 69, 70, 73, 92, 93, 106, | ||
3626 | 107, 108, 109, 110, 111, 112, 136, 138, 149, 77, 166, 167, 168 } ; | ||
3627 | /* | ||
3628 | u8 RegAddr[171]; | ||
3629 | for (i = 0; i <= 170; i++) | ||
3630 | RegAddr[i] = i; | ||
3631 | */ | ||
3632 | #endif | ||
3633 | |||
3634 | *count = ARRAY_SIZE(RegAddr); | ||
3635 | |||
3636 | for (i = 0 ; i < *count; i++) { | ||
3637 | RegNum[i] = RegAddr[i]; | ||
3638 | status += MXL_RegRead(fe, RegNum[i], &RegVal[i]); | ||
3639 | } | ||
3640 | |||
3641 | return status; | ||
3642 | } | ||
3643 | |||
3644 | static u16 MXL_GetCHRegister_ZeroIF(struct dvb_frontend *fe, u8 *RegNum, | ||
3645 | u8 *RegVal, int *count) | ||
3646 | { | ||
3647 | u16 status = 0; | ||
3648 | int i; | ||
3649 | |||
3650 | u8 RegAddr[] = {43, 136}; | ||
3651 | |||
3652 | *count = ARRAY_SIZE(RegAddr); | ||
3653 | |||
3654 | for (i = 0; i < *count; i++) { | ||
3655 | RegNum[i] = RegAddr[i]; | ||
3656 | status += MXL_RegRead(fe, RegNum[i], &RegVal[i]); | ||
3657 | } | ||
3658 | |||
3659 | return status; | ||
3660 | } | ||
3661 | |||
3662 | static u16 MXL_GetMasterControl(u8 *MasterReg, int state) | ||
3663 | { | ||
3664 | if (state == 1) /* Load_Start */ | ||
3665 | *MasterReg = 0xF3; | ||
3666 | if (state == 2) /* Power_Down */ | ||
3667 | *MasterReg = 0x41; | ||
3668 | if (state == 3) /* Synth_Reset */ | ||
3669 | *MasterReg = 0xB1; | ||
3670 | if (state == 4) /* Seq_Off */ | ||
3671 | *MasterReg = 0xF1; | ||
3672 | |||
3673 | return 0; | ||
3674 | } | ||
3675 | |||
3676 | #ifdef _MXL_PRODUCTION | ||
3677 | static u16 MXL_VCORange_Test(struct dvb_frontend *fe, int VCO_Range) | ||
3678 | { | ||
3679 | struct mxl5005s_state *state = fe->tuner_priv; | ||
3680 | u16 status = 0 ; | ||
3681 | |||
3682 | if (VCO_Range == 1) { | ||
3683 | status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1); | ||
3684 | status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); | ||
3685 | status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); | ||
3686 | status += MXL_ControlWrite(fe, RFSYN_DIVM, 1); | ||
3687 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); | ||
3688 | status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); | ||
3689 | status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); | ||
3690 | if (state->Mode == 0 && state->IF_Mode == 1) { | ||
3691 | /* Analog Low IF Mode */ | ||
3692 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); | ||
3693 | status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); | ||
3694 | status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 56); | ||
3695 | status += MXL_ControlWrite(fe, | ||
3696 | CHCAL_FRAC_MOD_RF, 180224); | ||
3697 | } | ||
3698 | if (state->Mode == 0 && state->IF_Mode == 0) { | ||
3699 | /* Analog Zero IF Mode */ | ||
3700 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); | ||
3701 | status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); | ||
3702 | status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 56); | ||
3703 | status += MXL_ControlWrite(fe, | ||
3704 | CHCAL_FRAC_MOD_RF, 222822); | ||
3705 | } | ||
3706 | if (state->Mode == 1) /* Digital Mode */ { | ||
3707 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); | ||
3708 | status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); | ||
3709 | status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 56); | ||
3710 | status += MXL_ControlWrite(fe, | ||
3711 | CHCAL_FRAC_MOD_RF, 229376); | ||
3712 | } | ||
3713 | } | ||
3714 | |||
3715 | if (VCO_Range == 2) { | ||
3716 | status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1); | ||
3717 | status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); | ||
3718 | status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); | ||
3719 | status += MXL_ControlWrite(fe, RFSYN_DIVM, 1); | ||
3720 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); | ||
3721 | status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); | ||
3722 | status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); | ||
3723 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); | ||
3724 | status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); | ||
3725 | status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 41); | ||
3726 | if (state->Mode == 0 && state->IF_Mode == 1) { | ||
3727 | /* Analog Low IF Mode */ | ||
3728 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); | ||
3729 | status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); | ||
3730 | status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42); | ||
3731 | status += MXL_ControlWrite(fe, | ||
3732 | CHCAL_FRAC_MOD_RF, 206438); | ||
3733 | } | ||
3734 | if (state->Mode == 0 && state->IF_Mode == 0) { | ||
3735 | /* Analog Zero IF Mode */ | ||
3736 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); | ||
3737 | status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); | ||
3738 | status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42); | ||
3739 | status += MXL_ControlWrite(fe, | ||
3740 | CHCAL_FRAC_MOD_RF, 206438); | ||
3741 | } | ||
3742 | if (state->Mode == 1) /* Digital Mode */ { | ||
3743 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 1); | ||
3744 | status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); | ||
3745 | status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 41); | ||
3746 | status += MXL_ControlWrite(fe, | ||
3747 | CHCAL_FRAC_MOD_RF, 16384); | ||
3748 | } | ||
3749 | } | ||
3750 | |||
3751 | if (VCO_Range == 3) { | ||
3752 | status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1); | ||
3753 | status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); | ||
3754 | status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); | ||
3755 | status += MXL_ControlWrite(fe, RFSYN_DIVM, 1); | ||
3756 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); | ||
3757 | status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); | ||
3758 | status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); | ||
3759 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); | ||
3760 | status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); | ||
3761 | status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42); | ||
3762 | if (state->Mode == 0 && state->IF_Mode == 1) { | ||
3763 | /* Analog Low IF Mode */ | ||
3764 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); | ||
3765 | status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); | ||
3766 | status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 44); | ||
3767 | status += MXL_ControlWrite(fe, | ||
3768 | CHCAL_FRAC_MOD_RF, 173670); | ||
3769 | } | ||
3770 | if (state->Mode == 0 && state->IF_Mode == 0) { | ||
3771 | /* Analog Zero IF Mode */ | ||
3772 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); | ||
3773 | status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); | ||
3774 | status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 44); | ||
3775 | status += MXL_ControlWrite(fe, | ||
3776 | CHCAL_FRAC_MOD_RF, 173670); | ||
3777 | } | ||
3778 | if (state->Mode == 1) /* Digital Mode */ { | ||
3779 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); | ||
3780 | status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 8); | ||
3781 | status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 42); | ||
3782 | status += MXL_ControlWrite(fe, | ||
3783 | CHCAL_FRAC_MOD_RF, 245760); | ||
3784 | } | ||
3785 | } | ||
3786 | |||
3787 | if (VCO_Range == 4) { | ||
3788 | status += MXL_ControlWrite(fe, RFSYN_EN_DIV, 1); | ||
3789 | status += MXL_ControlWrite(fe, RFSYN_EN_OUTMUX, 0); | ||
3790 | status += MXL_ControlWrite(fe, RFSYN_SEL_DIVM, 0); | ||
3791 | status += MXL_ControlWrite(fe, RFSYN_DIVM, 1); | ||
3792 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_OUT, 1); | ||
3793 | status += MXL_ControlWrite(fe, RFSYN_RF_DIV_BIAS, 1); | ||
3794 | status += MXL_ControlWrite(fe, DN_SEL_FREQ, 0); | ||
3795 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); | ||
3796 | status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); | ||
3797 | status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27); | ||
3798 | if (state->Mode == 0 && state->IF_Mode == 1) { | ||
3799 | /* Analog Low IF Mode */ | ||
3800 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); | ||
3801 | status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); | ||
3802 | status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27); | ||
3803 | status += MXL_ControlWrite(fe, | ||
3804 | CHCAL_FRAC_MOD_RF, 206438); | ||
3805 | } | ||
3806 | if (state->Mode == 0 && state->IF_Mode == 0) { | ||
3807 | /* Analog Zero IF Mode */ | ||
3808 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); | ||
3809 | status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); | ||
3810 | status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27); | ||
3811 | status += MXL_ControlWrite(fe, | ||
3812 | CHCAL_FRAC_MOD_RF, 206438); | ||
3813 | } | ||
3814 | if (state->Mode == 1) /* Digital Mode */ { | ||
3815 | status += MXL_ControlWrite(fe, RFSYN_SEL_VCO_HI, 0); | ||
3816 | status += MXL_ControlWrite(fe, RFSYN_VCO_BIAS, 40); | ||
3817 | status += MXL_ControlWrite(fe, CHCAL_INT_MOD_RF, 27); | ||
3818 | status += MXL_ControlWrite(fe, | ||
3819 | CHCAL_FRAC_MOD_RF, 212992); | ||
3820 | } | ||
3821 | } | ||
3822 | |||
3823 | return status; | ||
3824 | } | ||
3825 | |||
3826 | static u16 MXL_Hystersis_Test(struct dvb_frontend *fe, int Hystersis) | ||
3827 | { | ||
3828 | struct mxl5005s_state *state = fe->tuner_priv; | ||
3829 | u16 status = 0; | ||
3830 | |||
3831 | if (Hystersis == 1) | ||
3832 | status += MXL_ControlWrite(fe, DN_BYPASS_AGC_I2C, 1); | ||
3833 | |||
3834 | return status; | ||
3835 | } | ||
3836 | #endif | ||
3837 | /* End: Reference driver code found in the Realtek driver that | ||
3838 | * is copyright MaxLinear */ | ||
3839 | |||
3840 | /* ---------------------------------------------------------------- | ||
3841 | * Begin: Everything after here is new code to adapt the | ||
3842 | * proprietary Realtek driver into a Linux API tuner. | ||
3843 | * Copyright (C) 2008 Steven Toth <stoth@linuxtv.org> | ||
3844 | */ | ||
3845 | static int mxl5005s_reset(struct dvb_frontend *fe) | ||
3846 | { | ||
3847 | struct mxl5005s_state *state = fe->tuner_priv; | ||
3848 | int ret = 0; | ||
3849 | |||
3850 | u8 buf[2] = { 0xff, 0x00 }; | ||
3851 | struct i2c_msg msg = { .addr = state->config->i2c_address, .flags = 0, | ||
3852 | .buf = buf, .len = 2 }; | ||
3853 | |||
3854 | dprintk(2, "%s()\n", __func__); | ||
3855 | |||
3856 | if (fe->ops.i2c_gate_ctrl) | ||
3857 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
3858 | |||
3859 | if (i2c_transfer(state->i2c, &msg, 1) != 1) { | ||
3860 | printk(KERN_WARNING "mxl5005s I2C reset failed\n"); | ||
3861 | ret = -EREMOTEIO; | ||
3862 | } | ||
3863 | |||
3864 | if (fe->ops.i2c_gate_ctrl) | ||
3865 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
3866 | |||
3867 | return ret; | ||
3868 | } | ||
3869 | |||
3870 | /* Write a single byte to a single reg, latch the value if required by | ||
3871 | * following the transaction with the latch byte. | ||
3872 | */ | ||
3873 | static int mxl5005s_writereg(struct dvb_frontend *fe, u8 reg, u8 val, int latch) | ||
3874 | { | ||
3875 | struct mxl5005s_state *state = fe->tuner_priv; | ||
3876 | u8 buf[3] = { reg, val, MXL5005S_LATCH_BYTE }; | ||
3877 | struct i2c_msg msg = { .addr = state->config->i2c_address, .flags = 0, | ||
3878 | .buf = buf, .len = 3 }; | ||
3879 | |||
3880 | if (latch == 0) | ||
3881 | msg.len = 2; | ||
3882 | |||
3883 | dprintk(2, "%s(0x%x, 0x%x, 0x%x)\n", __func__, reg, val, msg.addr); | ||
3884 | |||
3885 | if (i2c_transfer(state->i2c, &msg, 1) != 1) { | ||
3886 | printk(KERN_WARNING "mxl5005s I2C write failed\n"); | ||
3887 | return -EREMOTEIO; | ||
3888 | } | ||
3889 | return 0; | ||
3890 | } | ||
3891 | |||
3892 | static int mxl5005s_writeregs(struct dvb_frontend *fe, u8 *addrtable, | ||
3893 | u8 *datatable, u8 len) | ||
3894 | { | ||
3895 | int ret = 0, i; | ||
3896 | |||
3897 | if (fe->ops.i2c_gate_ctrl) | ||
3898 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
3899 | |||
3900 | for (i = 0 ; i < len-1; i++) { | ||
3901 | ret = mxl5005s_writereg(fe, addrtable[i], datatable[i], 0); | ||
3902 | if (ret < 0) | ||
3903 | break; | ||
3904 | } | ||
3905 | |||
3906 | ret = mxl5005s_writereg(fe, addrtable[i], datatable[i], 1); | ||
3907 | |||
3908 | if (fe->ops.i2c_gate_ctrl) | ||
3909 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
3910 | |||
3911 | return ret; | ||
3912 | } | ||
3913 | |||
3914 | static int mxl5005s_init(struct dvb_frontend *fe) | ||
3915 | { | ||
3916 | struct mxl5005s_state *state = fe->tuner_priv; | ||
3917 | |||
3918 | dprintk(1, "%s()\n", __func__); | ||
3919 | state->current_mode = MXL_QAM; | ||
3920 | return mxl5005s_reconfigure(fe, MXL_QAM, MXL5005S_BANDWIDTH_6MHZ); | ||
3921 | } | ||
3922 | |||
3923 | static int mxl5005s_reconfigure(struct dvb_frontend *fe, u32 mod_type, | ||
3924 | u32 bandwidth) | ||
3925 | { | ||
3926 | struct mxl5005s_state *state = fe->tuner_priv; | ||
3927 | |||
3928 | u8 AddrTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX]; | ||
3929 | u8 ByteTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX]; | ||
3930 | int TableLen; | ||
3931 | |||
3932 | dprintk(1, "%s(type=%d, bw=%d)\n", __func__, mod_type, bandwidth); | ||
3933 | |||
3934 | mxl5005s_reset(fe); | ||
3935 | |||
3936 | /* Tuner initialization stage 0 */ | ||
3937 | MXL_GetMasterControl(ByteTable, MC_SYNTH_RESET); | ||
3938 | AddrTable[0] = MASTER_CONTROL_ADDR; | ||
3939 | ByteTable[0] |= state->config->AgcMasterByte; | ||
3940 | |||
3941 | mxl5005s_writeregs(fe, AddrTable, ByteTable, 1); | ||
3942 | |||
3943 | mxl5005s_AssignTunerMode(fe, mod_type, bandwidth); | ||
3944 | |||
3945 | /* Tuner initialization stage 1 */ | ||
3946 | MXL_GetInitRegister(fe, AddrTable, ByteTable, &TableLen); | ||
3947 | |||
3948 | mxl5005s_writeregs(fe, AddrTable, ByteTable, TableLen); | ||
3949 | |||
3950 | return 0; | ||
3951 | } | ||
3952 | |||
3953 | static int mxl5005s_AssignTunerMode(struct dvb_frontend *fe, u32 mod_type, | ||
3954 | u32 bandwidth) | ||
3955 | { | ||
3956 | struct mxl5005s_state *state = fe->tuner_priv; | ||
3957 | struct mxl5005s_config *c = state->config; | ||
3958 | |||
3959 | InitTunerControls(fe); | ||
3960 | |||
3961 | /* Set MxL5005S parameters. */ | ||
3962 | MXL5005_TunerConfig( | ||
3963 | fe, | ||
3964 | c->mod_mode, | ||
3965 | c->if_mode, | ||
3966 | bandwidth, | ||
3967 | c->if_freq, | ||
3968 | c->xtal_freq, | ||
3969 | c->agc_mode, | ||
3970 | c->top, | ||
3971 | c->output_load, | ||
3972 | c->clock_out, | ||
3973 | c->div_out, | ||
3974 | c->cap_select, | ||
3975 | c->rssi_enable, | ||
3976 | mod_type, | ||
3977 | c->tracking_filter); | ||
3978 | |||
3979 | return 0; | ||
3980 | } | ||
3981 | |||
3982 | static int mxl5005s_set_params(struct dvb_frontend *fe) | ||
3983 | { | ||
3984 | struct mxl5005s_state *state = fe->tuner_priv; | ||
3985 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
3986 | u32 delsys = c->delivery_system; | ||
3987 | u32 bw = c->bandwidth_hz; | ||
3988 | u32 req_mode, req_bw = 0; | ||
3989 | int ret; | ||
3990 | |||
3991 | dprintk(1, "%s()\n", __func__); | ||
3992 | |||
3993 | switch (delsys) { | ||
3994 | case SYS_ATSC: | ||
3995 | req_mode = MXL_ATSC; | ||
3996 | req_bw = MXL5005S_BANDWIDTH_6MHZ; | ||
3997 | break; | ||
3998 | case SYS_DVBC_ANNEX_B: | ||
3999 | req_mode = MXL_QAM; | ||
4000 | req_bw = MXL5005S_BANDWIDTH_6MHZ; | ||
4001 | break; | ||
4002 | default: /* Assume DVB-T */ | ||
4003 | req_mode = MXL_DVBT; | ||
4004 | switch (bw) { | ||
4005 | case 6000000: | ||
4006 | req_bw = MXL5005S_BANDWIDTH_6MHZ; | ||
4007 | break; | ||
4008 | case 7000000: | ||
4009 | req_bw = MXL5005S_BANDWIDTH_7MHZ; | ||
4010 | break; | ||
4011 | case 8000000: | ||
4012 | case 0: | ||
4013 | req_bw = MXL5005S_BANDWIDTH_8MHZ; | ||
4014 | break; | ||
4015 | default: | ||
4016 | return -EINVAL; | ||
4017 | } | ||
4018 | } | ||
4019 | |||
4020 | /* Change tuner for new modulation type if reqd */ | ||
4021 | if (req_mode != state->current_mode || | ||
4022 | req_bw != state->Chan_Bandwidth) { | ||
4023 | state->current_mode = req_mode; | ||
4024 | ret = mxl5005s_reconfigure(fe, req_mode, req_bw); | ||
4025 | |||
4026 | } else | ||
4027 | ret = 0; | ||
4028 | |||
4029 | if (ret == 0) { | ||
4030 | dprintk(1, "%s() freq=%d\n", __func__, c->frequency); | ||
4031 | ret = mxl5005s_SetRfFreqHz(fe, c->frequency); | ||
4032 | } | ||
4033 | |||
4034 | return ret; | ||
4035 | } | ||
4036 | |||
4037 | static int mxl5005s_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
4038 | { | ||
4039 | struct mxl5005s_state *state = fe->tuner_priv; | ||
4040 | dprintk(1, "%s()\n", __func__); | ||
4041 | |||
4042 | *frequency = state->RF_IN; | ||
4043 | |||
4044 | return 0; | ||
4045 | } | ||
4046 | |||
4047 | static int mxl5005s_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) | ||
4048 | { | ||
4049 | struct mxl5005s_state *state = fe->tuner_priv; | ||
4050 | dprintk(1, "%s()\n", __func__); | ||
4051 | |||
4052 | *bandwidth = state->Chan_Bandwidth; | ||
4053 | |||
4054 | return 0; | ||
4055 | } | ||
4056 | |||
4057 | static int mxl5005s_release(struct dvb_frontend *fe) | ||
4058 | { | ||
4059 | dprintk(1, "%s()\n", __func__); | ||
4060 | kfree(fe->tuner_priv); | ||
4061 | fe->tuner_priv = NULL; | ||
4062 | return 0; | ||
4063 | } | ||
4064 | |||
4065 | static const struct dvb_tuner_ops mxl5005s_tuner_ops = { | ||
4066 | .info = { | ||
4067 | .name = "MaxLinear MXL5005S", | ||
4068 | .frequency_min = 48000000, | ||
4069 | .frequency_max = 860000000, | ||
4070 | .frequency_step = 50000, | ||
4071 | }, | ||
4072 | |||
4073 | .release = mxl5005s_release, | ||
4074 | .init = mxl5005s_init, | ||
4075 | |||
4076 | .set_params = mxl5005s_set_params, | ||
4077 | .get_frequency = mxl5005s_get_frequency, | ||
4078 | .get_bandwidth = mxl5005s_get_bandwidth, | ||
4079 | }; | ||
4080 | |||
4081 | struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe, | ||
4082 | struct i2c_adapter *i2c, | ||
4083 | struct mxl5005s_config *config) | ||
4084 | { | ||
4085 | struct mxl5005s_state *state = NULL; | ||
4086 | dprintk(1, "%s()\n", __func__); | ||
4087 | |||
4088 | state = kzalloc(sizeof(struct mxl5005s_state), GFP_KERNEL); | ||
4089 | if (state == NULL) | ||
4090 | return NULL; | ||
4091 | |||
4092 | state->frontend = fe; | ||
4093 | state->config = config; | ||
4094 | state->i2c = i2c; | ||
4095 | |||
4096 | printk(KERN_INFO "MXL5005S: Attached at address 0x%02x\n", | ||
4097 | config->i2c_address); | ||
4098 | |||
4099 | memcpy(&fe->ops.tuner_ops, &mxl5005s_tuner_ops, | ||
4100 | sizeof(struct dvb_tuner_ops)); | ||
4101 | |||
4102 | fe->tuner_priv = state; | ||
4103 | return fe; | ||
4104 | } | ||
4105 | EXPORT_SYMBOL(mxl5005s_attach); | ||
4106 | |||
4107 | MODULE_DESCRIPTION("MaxLinear MXL5005S silicon tuner driver"); | ||
4108 | MODULE_AUTHOR("Steven Toth"); | ||
4109 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/tuners/mxl5005s.h b/drivers/media/tuners/mxl5005s.h new file mode 100644 index 000000000000..fc8a1ffc53b4 --- /dev/null +++ b/drivers/media/tuners/mxl5005s.h | |||
@@ -0,0 +1,135 @@ | |||
1 | /* | ||
2 | MaxLinear MXL5005S VSB/QAM/DVBT tuner driver | ||
3 | |||
4 | Copyright (C) 2008 MaxLinear | ||
5 | Copyright (C) 2008 Steven Toth <stoth@linuxtv.org> | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
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 | |||
23 | #ifndef __MXL5005S_H | ||
24 | #define __MXL5005S_H | ||
25 | |||
26 | #include <linux/i2c.h> | ||
27 | #include "dvb_frontend.h" | ||
28 | |||
29 | struct mxl5005s_config { | ||
30 | |||
31 | /* 7 bit i2c address */ | ||
32 | u8 i2c_address; | ||
33 | |||
34 | #define IF_FREQ_4570000HZ 4570000 | ||
35 | #define IF_FREQ_4571429HZ 4571429 | ||
36 | #define IF_FREQ_5380000HZ 5380000 | ||
37 | #define IF_FREQ_36000000HZ 36000000 | ||
38 | #define IF_FREQ_36125000HZ 36125000 | ||
39 | #define IF_FREQ_36166667HZ 36166667 | ||
40 | #define IF_FREQ_44000000HZ 44000000 | ||
41 | u32 if_freq; | ||
42 | |||
43 | #define CRYSTAL_FREQ_4000000HZ 4000000 | ||
44 | #define CRYSTAL_FREQ_16000000HZ 16000000 | ||
45 | #define CRYSTAL_FREQ_25000000HZ 25000000 | ||
46 | #define CRYSTAL_FREQ_28800000HZ 28800000 | ||
47 | u32 xtal_freq; | ||
48 | |||
49 | #define MXL_DUAL_AGC 0 | ||
50 | #define MXL_SINGLE_AGC 1 | ||
51 | u8 agc_mode; | ||
52 | |||
53 | #define MXL_TF_DEFAULT 0 | ||
54 | #define MXL_TF_OFF 1 | ||
55 | #define MXL_TF_C 2 | ||
56 | #define MXL_TF_C_H 3 | ||
57 | #define MXL_TF_D 4 | ||
58 | #define MXL_TF_D_L 5 | ||
59 | #define MXL_TF_E 6 | ||
60 | #define MXL_TF_F 7 | ||
61 | #define MXL_TF_E_2 8 | ||
62 | #define MXL_TF_E_NA 9 | ||
63 | #define MXL_TF_G 10 | ||
64 | u8 tracking_filter; | ||
65 | |||
66 | #define MXL_RSSI_DISABLE 0 | ||
67 | #define MXL_RSSI_ENABLE 1 | ||
68 | u8 rssi_enable; | ||
69 | |||
70 | #define MXL_CAP_SEL_DISABLE 0 | ||
71 | #define MXL_CAP_SEL_ENABLE 1 | ||
72 | u8 cap_select; | ||
73 | |||
74 | #define MXL_DIV_OUT_1 0 | ||
75 | #define MXL_DIV_OUT_4 1 | ||
76 | u8 div_out; | ||
77 | |||
78 | #define MXL_CLOCK_OUT_DISABLE 0 | ||
79 | #define MXL_CLOCK_OUT_ENABLE 1 | ||
80 | u8 clock_out; | ||
81 | |||
82 | #define MXL5005S_IF_OUTPUT_LOAD_200_OHM 200 | ||
83 | #define MXL5005S_IF_OUTPUT_LOAD_300_OHM 300 | ||
84 | u32 output_load; | ||
85 | |||
86 | #define MXL5005S_TOP_5P5 55 | ||
87 | #define MXL5005S_TOP_7P2 72 | ||
88 | #define MXL5005S_TOP_9P2 92 | ||
89 | #define MXL5005S_TOP_11P0 110 | ||
90 | #define MXL5005S_TOP_12P9 129 | ||
91 | #define MXL5005S_TOP_14P7 147 | ||
92 | #define MXL5005S_TOP_16P8 168 | ||
93 | #define MXL5005S_TOP_19P4 194 | ||
94 | #define MXL5005S_TOP_21P2 212 | ||
95 | #define MXL5005S_TOP_23P2 232 | ||
96 | #define MXL5005S_TOP_25P2 252 | ||
97 | #define MXL5005S_TOP_27P1 271 | ||
98 | #define MXL5005S_TOP_29P2 292 | ||
99 | #define MXL5005S_TOP_31P7 317 | ||
100 | #define MXL5005S_TOP_34P9 349 | ||
101 | u32 top; | ||
102 | |||
103 | #define MXL_ANALOG_MODE 0 | ||
104 | #define MXL_DIGITAL_MODE 1 | ||
105 | u8 mod_mode; | ||
106 | |||
107 | #define MXL_ZERO_IF 0 | ||
108 | #define MXL_LOW_IF 1 | ||
109 | u8 if_mode; | ||
110 | |||
111 | /* Some boards need to override the built-in logic for determining | ||
112 | the gain when in QAM mode (the HVR-1600 is one such case) */ | ||
113 | u8 qam_gain; | ||
114 | |||
115 | /* Stuff I don't know what to do with */ | ||
116 | u8 AgcMasterByte; | ||
117 | }; | ||
118 | |||
119 | #if defined(CONFIG_MEDIA_TUNER_MXL5005S) || \ | ||
120 | (defined(CONFIG_MEDIA_TUNER_MXL5005S_MODULE) && defined(MODULE)) | ||
121 | extern struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe, | ||
122 | struct i2c_adapter *i2c, | ||
123 | struct mxl5005s_config *config); | ||
124 | #else | ||
125 | static inline struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe, | ||
126 | struct i2c_adapter *i2c, | ||
127 | struct mxl5005s_config *config) | ||
128 | { | ||
129 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
130 | return NULL; | ||
131 | } | ||
132 | #endif /* CONFIG_DVB_TUNER_MXL5005S */ | ||
133 | |||
134 | #endif /* __MXL5005S_H */ | ||
135 | |||
diff --git a/drivers/media/tuners/mxl5007t.c b/drivers/media/tuners/mxl5007t.c new file mode 100644 index 000000000000..69e453ef0a1a --- /dev/null +++ b/drivers/media/tuners/mxl5007t.c | |||
@@ -0,0 +1,928 @@ | |||
1 | /* | ||
2 | * mxl5007t.c - driver for the MaxLinear MxL5007T silicon tuner | ||
3 | * | ||
4 | * Copyright (C) 2008, 2009 Michael Krufky <mkrufky@linuxtv.org> | ||
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 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/i2c.h> | ||
22 | #include <linux/types.h> | ||
23 | #include <linux/videodev2.h> | ||
24 | #include "tuner-i2c.h" | ||
25 | #include "mxl5007t.h" | ||
26 | |||
27 | static DEFINE_MUTEX(mxl5007t_list_mutex); | ||
28 | static LIST_HEAD(hybrid_tuner_instance_list); | ||
29 | |||
30 | static int mxl5007t_debug; | ||
31 | module_param_named(debug, mxl5007t_debug, int, 0644); | ||
32 | MODULE_PARM_DESC(debug, "set debug level"); | ||
33 | |||
34 | /* ------------------------------------------------------------------------- */ | ||
35 | |||
36 | #define mxl_printk(kern, fmt, arg...) \ | ||
37 | printk(kern "%s: " fmt "\n", __func__, ##arg) | ||
38 | |||
39 | #define mxl_err(fmt, arg...) \ | ||
40 | mxl_printk(KERN_ERR, "%d: " fmt, __LINE__, ##arg) | ||
41 | |||
42 | #define mxl_warn(fmt, arg...) \ | ||
43 | mxl_printk(KERN_WARNING, fmt, ##arg) | ||
44 | |||
45 | #define mxl_info(fmt, arg...) \ | ||
46 | mxl_printk(KERN_INFO, fmt, ##arg) | ||
47 | |||
48 | #define mxl_debug(fmt, arg...) \ | ||
49 | ({ \ | ||
50 | if (mxl5007t_debug) \ | ||
51 | mxl_printk(KERN_DEBUG, fmt, ##arg); \ | ||
52 | }) | ||
53 | |||
54 | #define mxl_fail(ret) \ | ||
55 | ({ \ | ||
56 | int __ret; \ | ||
57 | __ret = (ret < 0); \ | ||
58 | if (__ret) \ | ||
59 | mxl_printk(KERN_ERR, "error %d on line %d", \ | ||
60 | ret, __LINE__); \ | ||
61 | __ret; \ | ||
62 | }) | ||
63 | |||
64 | /* ------------------------------------------------------------------------- */ | ||
65 | |||
66 | #define MHz 1000000 | ||
67 | |||
68 | enum mxl5007t_mode { | ||
69 | MxL_MODE_ISDBT = 0, | ||
70 | MxL_MODE_DVBT = 1, | ||
71 | MxL_MODE_ATSC = 2, | ||
72 | MxL_MODE_CABLE = 0x10, | ||
73 | }; | ||
74 | |||
75 | enum mxl5007t_chip_version { | ||
76 | MxL_UNKNOWN_ID = 0x00, | ||
77 | MxL_5007_V1_F1 = 0x11, | ||
78 | MxL_5007_V1_F2 = 0x12, | ||
79 | MxL_5007_V4 = 0x14, | ||
80 | MxL_5007_V2_100_F1 = 0x21, | ||
81 | MxL_5007_V2_100_F2 = 0x22, | ||
82 | MxL_5007_V2_200_F1 = 0x23, | ||
83 | MxL_5007_V2_200_F2 = 0x24, | ||
84 | }; | ||
85 | |||
86 | struct reg_pair_t { | ||
87 | u8 reg; | ||
88 | u8 val; | ||
89 | }; | ||
90 | |||
91 | /* ------------------------------------------------------------------------- */ | ||
92 | |||
93 | static struct reg_pair_t init_tab[] = { | ||
94 | { 0x02, 0x06 }, | ||
95 | { 0x03, 0x48 }, | ||
96 | { 0x05, 0x04 }, | ||
97 | { 0x06, 0x10 }, | ||
98 | { 0x2e, 0x15 }, /* OVERRIDE */ | ||
99 | { 0x30, 0x10 }, /* OVERRIDE */ | ||
100 | { 0x45, 0x58 }, /* OVERRIDE */ | ||
101 | { 0x48, 0x19 }, /* OVERRIDE */ | ||
102 | { 0x52, 0x03 }, /* OVERRIDE */ | ||
103 | { 0x53, 0x44 }, /* OVERRIDE */ | ||
104 | { 0x6a, 0x4b }, /* OVERRIDE */ | ||
105 | { 0x76, 0x00 }, /* OVERRIDE */ | ||
106 | { 0x78, 0x18 }, /* OVERRIDE */ | ||
107 | { 0x7a, 0x17 }, /* OVERRIDE */ | ||
108 | { 0x85, 0x06 }, /* OVERRIDE */ | ||
109 | { 0x01, 0x01 }, /* TOP_MASTER_ENABLE */ | ||
110 | { 0, 0 } | ||
111 | }; | ||
112 | |||
113 | static struct reg_pair_t init_tab_cable[] = { | ||
114 | { 0x02, 0x06 }, | ||
115 | { 0x03, 0x48 }, | ||
116 | { 0x05, 0x04 }, | ||
117 | { 0x06, 0x10 }, | ||
118 | { 0x09, 0x3f }, | ||
119 | { 0x0a, 0x3f }, | ||
120 | { 0x0b, 0x3f }, | ||
121 | { 0x2e, 0x15 }, /* OVERRIDE */ | ||
122 | { 0x30, 0x10 }, /* OVERRIDE */ | ||
123 | { 0x45, 0x58 }, /* OVERRIDE */ | ||
124 | { 0x48, 0x19 }, /* OVERRIDE */ | ||
125 | { 0x52, 0x03 }, /* OVERRIDE */ | ||
126 | { 0x53, 0x44 }, /* OVERRIDE */ | ||
127 | { 0x6a, 0x4b }, /* OVERRIDE */ | ||
128 | { 0x76, 0x00 }, /* OVERRIDE */ | ||
129 | { 0x78, 0x18 }, /* OVERRIDE */ | ||
130 | { 0x7a, 0x17 }, /* OVERRIDE */ | ||
131 | { 0x85, 0x06 }, /* OVERRIDE */ | ||
132 | { 0x01, 0x01 }, /* TOP_MASTER_ENABLE */ | ||
133 | { 0, 0 } | ||
134 | }; | ||
135 | |||
136 | /* ------------------------------------------------------------------------- */ | ||
137 | |||
138 | static struct reg_pair_t reg_pair_rftune[] = { | ||
139 | { 0x0f, 0x00 }, /* abort tune */ | ||
140 | { 0x0c, 0x15 }, | ||
141 | { 0x0d, 0x40 }, | ||
142 | { 0x0e, 0x0e }, | ||
143 | { 0x1f, 0x87 }, /* OVERRIDE */ | ||
144 | { 0x20, 0x1f }, /* OVERRIDE */ | ||
145 | { 0x21, 0x87 }, /* OVERRIDE */ | ||
146 | { 0x22, 0x1f }, /* OVERRIDE */ | ||
147 | { 0x80, 0x01 }, /* freq dependent */ | ||
148 | { 0x0f, 0x01 }, /* start tune */ | ||
149 | { 0, 0 } | ||
150 | }; | ||
151 | |||
152 | /* ------------------------------------------------------------------------- */ | ||
153 | |||
154 | struct mxl5007t_state { | ||
155 | struct list_head hybrid_tuner_instance_list; | ||
156 | struct tuner_i2c_props i2c_props; | ||
157 | |||
158 | struct mutex lock; | ||
159 | |||
160 | struct mxl5007t_config *config; | ||
161 | |||
162 | enum mxl5007t_chip_version chip_id; | ||
163 | |||
164 | struct reg_pair_t tab_init[ARRAY_SIZE(init_tab)]; | ||
165 | struct reg_pair_t tab_init_cable[ARRAY_SIZE(init_tab_cable)]; | ||
166 | struct reg_pair_t tab_rftune[ARRAY_SIZE(reg_pair_rftune)]; | ||
167 | |||
168 | enum mxl5007t_if_freq if_freq; | ||
169 | |||
170 | u32 frequency; | ||
171 | u32 bandwidth; | ||
172 | }; | ||
173 | |||
174 | /* ------------------------------------------------------------------------- */ | ||
175 | |||
176 | /* called by _init and _rftun to manipulate the register arrays */ | ||
177 | |||
178 | static void set_reg_bits(struct reg_pair_t *reg_pair, u8 reg, u8 mask, u8 val) | ||
179 | { | ||
180 | unsigned int i = 0; | ||
181 | |||
182 | while (reg_pair[i].reg || reg_pair[i].val) { | ||
183 | if (reg_pair[i].reg == reg) { | ||
184 | reg_pair[i].val &= ~mask; | ||
185 | reg_pair[i].val |= val; | ||
186 | } | ||
187 | i++; | ||
188 | |||
189 | } | ||
190 | return; | ||
191 | } | ||
192 | |||
193 | static void copy_reg_bits(struct reg_pair_t *reg_pair1, | ||
194 | struct reg_pair_t *reg_pair2) | ||
195 | { | ||
196 | unsigned int i, j; | ||
197 | |||
198 | i = j = 0; | ||
199 | |||
200 | while (reg_pair1[i].reg || reg_pair1[i].val) { | ||
201 | while (reg_pair2[j].reg || reg_pair2[j].val) { | ||
202 | if (reg_pair1[i].reg != reg_pair2[j].reg) { | ||
203 | j++; | ||
204 | continue; | ||
205 | } | ||
206 | reg_pair2[j].val = reg_pair1[i].val; | ||
207 | break; | ||
208 | } | ||
209 | i++; | ||
210 | } | ||
211 | return; | ||
212 | } | ||
213 | |||
214 | /* ------------------------------------------------------------------------- */ | ||
215 | |||
216 | static void mxl5007t_set_mode_bits(struct mxl5007t_state *state, | ||
217 | enum mxl5007t_mode mode, | ||
218 | s32 if_diff_out_level) | ||
219 | { | ||
220 | switch (mode) { | ||
221 | case MxL_MODE_ATSC: | ||
222 | set_reg_bits(state->tab_init, 0x06, 0x1f, 0x12); | ||
223 | break; | ||
224 | case MxL_MODE_DVBT: | ||
225 | set_reg_bits(state->tab_init, 0x06, 0x1f, 0x11); | ||
226 | break; | ||
227 | case MxL_MODE_ISDBT: | ||
228 | set_reg_bits(state->tab_init, 0x06, 0x1f, 0x10); | ||
229 | break; | ||
230 | case MxL_MODE_CABLE: | ||
231 | set_reg_bits(state->tab_init_cable, 0x09, 0xff, 0xc1); | ||
232 | set_reg_bits(state->tab_init_cable, 0x0a, 0xff, | ||
233 | 8 - if_diff_out_level); | ||
234 | set_reg_bits(state->tab_init_cable, 0x0b, 0xff, 0x17); | ||
235 | break; | ||
236 | default: | ||
237 | mxl_fail(-EINVAL); | ||
238 | } | ||
239 | return; | ||
240 | } | ||
241 | |||
242 | static void mxl5007t_set_if_freq_bits(struct mxl5007t_state *state, | ||
243 | enum mxl5007t_if_freq if_freq, | ||
244 | int invert_if) | ||
245 | { | ||
246 | u8 val; | ||
247 | |||
248 | switch (if_freq) { | ||
249 | case MxL_IF_4_MHZ: | ||
250 | val = 0x00; | ||
251 | break; | ||
252 | case MxL_IF_4_5_MHZ: | ||
253 | val = 0x02; | ||
254 | break; | ||
255 | case MxL_IF_4_57_MHZ: | ||
256 | val = 0x03; | ||
257 | break; | ||
258 | case MxL_IF_5_MHZ: | ||
259 | val = 0x04; | ||
260 | break; | ||
261 | case MxL_IF_5_38_MHZ: | ||
262 | val = 0x05; | ||
263 | break; | ||
264 | case MxL_IF_6_MHZ: | ||
265 | val = 0x06; | ||
266 | break; | ||
267 | case MxL_IF_6_28_MHZ: | ||
268 | val = 0x07; | ||
269 | break; | ||
270 | case MxL_IF_9_1915_MHZ: | ||
271 | val = 0x08; | ||
272 | break; | ||
273 | case MxL_IF_35_25_MHZ: | ||
274 | val = 0x09; | ||
275 | break; | ||
276 | case MxL_IF_36_15_MHZ: | ||
277 | val = 0x0a; | ||
278 | break; | ||
279 | case MxL_IF_44_MHZ: | ||
280 | val = 0x0b; | ||
281 | break; | ||
282 | default: | ||
283 | mxl_fail(-EINVAL); | ||
284 | return; | ||
285 | } | ||
286 | set_reg_bits(state->tab_init, 0x02, 0x0f, val); | ||
287 | |||
288 | /* set inverted IF or normal IF */ | ||
289 | set_reg_bits(state->tab_init, 0x02, 0x10, invert_if ? 0x10 : 0x00); | ||
290 | |||
291 | state->if_freq = if_freq; | ||
292 | |||
293 | return; | ||
294 | } | ||
295 | |||
296 | static void mxl5007t_set_xtal_freq_bits(struct mxl5007t_state *state, | ||
297 | enum mxl5007t_xtal_freq xtal_freq) | ||
298 | { | ||
299 | switch (xtal_freq) { | ||
300 | case MxL_XTAL_16_MHZ: | ||
301 | /* select xtal freq & ref freq */ | ||
302 | set_reg_bits(state->tab_init, 0x03, 0xf0, 0x00); | ||
303 | set_reg_bits(state->tab_init, 0x05, 0x0f, 0x00); | ||
304 | break; | ||
305 | case MxL_XTAL_20_MHZ: | ||
306 | set_reg_bits(state->tab_init, 0x03, 0xf0, 0x10); | ||
307 | set_reg_bits(state->tab_init, 0x05, 0x0f, 0x01); | ||
308 | break; | ||
309 | case MxL_XTAL_20_25_MHZ: | ||
310 | set_reg_bits(state->tab_init, 0x03, 0xf0, 0x20); | ||
311 | set_reg_bits(state->tab_init, 0x05, 0x0f, 0x02); | ||
312 | break; | ||
313 | case MxL_XTAL_20_48_MHZ: | ||
314 | set_reg_bits(state->tab_init, 0x03, 0xf0, 0x30); | ||
315 | set_reg_bits(state->tab_init, 0x05, 0x0f, 0x03); | ||
316 | break; | ||
317 | case MxL_XTAL_24_MHZ: | ||
318 | set_reg_bits(state->tab_init, 0x03, 0xf0, 0x40); | ||
319 | set_reg_bits(state->tab_init, 0x05, 0x0f, 0x04); | ||
320 | break; | ||
321 | case MxL_XTAL_25_MHZ: | ||
322 | set_reg_bits(state->tab_init, 0x03, 0xf0, 0x50); | ||
323 | set_reg_bits(state->tab_init, 0x05, 0x0f, 0x05); | ||
324 | break; | ||
325 | case MxL_XTAL_25_14_MHZ: | ||
326 | set_reg_bits(state->tab_init, 0x03, 0xf0, 0x60); | ||
327 | set_reg_bits(state->tab_init, 0x05, 0x0f, 0x06); | ||
328 | break; | ||
329 | case MxL_XTAL_27_MHZ: | ||
330 | set_reg_bits(state->tab_init, 0x03, 0xf0, 0x70); | ||
331 | set_reg_bits(state->tab_init, 0x05, 0x0f, 0x07); | ||
332 | break; | ||
333 | case MxL_XTAL_28_8_MHZ: | ||
334 | set_reg_bits(state->tab_init, 0x03, 0xf0, 0x80); | ||
335 | set_reg_bits(state->tab_init, 0x05, 0x0f, 0x08); | ||
336 | break; | ||
337 | case MxL_XTAL_32_MHZ: | ||
338 | set_reg_bits(state->tab_init, 0x03, 0xf0, 0x90); | ||
339 | set_reg_bits(state->tab_init, 0x05, 0x0f, 0x09); | ||
340 | break; | ||
341 | case MxL_XTAL_40_MHZ: | ||
342 | set_reg_bits(state->tab_init, 0x03, 0xf0, 0xa0); | ||
343 | set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0a); | ||
344 | break; | ||
345 | case MxL_XTAL_44_MHZ: | ||
346 | set_reg_bits(state->tab_init, 0x03, 0xf0, 0xb0); | ||
347 | set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0b); | ||
348 | break; | ||
349 | case MxL_XTAL_48_MHZ: | ||
350 | set_reg_bits(state->tab_init, 0x03, 0xf0, 0xc0); | ||
351 | set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0c); | ||
352 | break; | ||
353 | case MxL_XTAL_49_3811_MHZ: | ||
354 | set_reg_bits(state->tab_init, 0x03, 0xf0, 0xd0); | ||
355 | set_reg_bits(state->tab_init, 0x05, 0x0f, 0x0d); | ||
356 | break; | ||
357 | default: | ||
358 | mxl_fail(-EINVAL); | ||
359 | return; | ||
360 | } | ||
361 | |||
362 | return; | ||
363 | } | ||
364 | |||
365 | static struct reg_pair_t *mxl5007t_calc_init_regs(struct mxl5007t_state *state, | ||
366 | enum mxl5007t_mode mode) | ||
367 | { | ||
368 | struct mxl5007t_config *cfg = state->config; | ||
369 | |||
370 | memcpy(&state->tab_init, &init_tab, sizeof(init_tab)); | ||
371 | memcpy(&state->tab_init_cable, &init_tab_cable, sizeof(init_tab_cable)); | ||
372 | |||
373 | mxl5007t_set_mode_bits(state, mode, cfg->if_diff_out_level); | ||
374 | mxl5007t_set_if_freq_bits(state, cfg->if_freq_hz, cfg->invert_if); | ||
375 | mxl5007t_set_xtal_freq_bits(state, cfg->xtal_freq_hz); | ||
376 | |||
377 | set_reg_bits(state->tab_init, 0x04, 0x01, cfg->loop_thru_enable); | ||
378 | set_reg_bits(state->tab_init, 0x03, 0x08, cfg->clk_out_enable << 3); | ||
379 | set_reg_bits(state->tab_init, 0x03, 0x07, cfg->clk_out_amp); | ||
380 | |||
381 | if (mode >= MxL_MODE_CABLE) { | ||
382 | copy_reg_bits(state->tab_init, state->tab_init_cable); | ||
383 | return state->tab_init_cable; | ||
384 | } else | ||
385 | return state->tab_init; | ||
386 | } | ||
387 | |||
388 | /* ------------------------------------------------------------------------- */ | ||
389 | |||
390 | enum mxl5007t_bw_mhz { | ||
391 | MxL_BW_6MHz = 6, | ||
392 | MxL_BW_7MHz = 7, | ||
393 | MxL_BW_8MHz = 8, | ||
394 | }; | ||
395 | |||
396 | static void mxl5007t_set_bw_bits(struct mxl5007t_state *state, | ||
397 | enum mxl5007t_bw_mhz bw) | ||
398 | { | ||
399 | u8 val; | ||
400 | |||
401 | switch (bw) { | ||
402 | case MxL_BW_6MHz: | ||
403 | val = 0x15; /* set DIG_MODEINDEX, DIG_MODEINDEX_A, | ||
404 | * and DIG_MODEINDEX_CSF */ | ||
405 | break; | ||
406 | case MxL_BW_7MHz: | ||
407 | val = 0x2a; | ||
408 | break; | ||
409 | case MxL_BW_8MHz: | ||
410 | val = 0x3f; | ||
411 | break; | ||
412 | default: | ||
413 | mxl_fail(-EINVAL); | ||
414 | return; | ||
415 | } | ||
416 | set_reg_bits(state->tab_rftune, 0x0c, 0x3f, val); | ||
417 | |||
418 | return; | ||
419 | } | ||
420 | |||
421 | static struct | ||
422 | reg_pair_t *mxl5007t_calc_rf_tune_regs(struct mxl5007t_state *state, | ||
423 | u32 rf_freq, enum mxl5007t_bw_mhz bw) | ||
424 | { | ||
425 | u32 dig_rf_freq = 0; | ||
426 | u32 temp; | ||
427 | u32 frac_divider = 1000000; | ||
428 | unsigned int i; | ||
429 | |||
430 | memcpy(&state->tab_rftune, ®_pair_rftune, sizeof(reg_pair_rftune)); | ||
431 | |||
432 | mxl5007t_set_bw_bits(state, bw); | ||
433 | |||
434 | /* Convert RF frequency into 16 bits => | ||
435 | * 10 bit integer (MHz) + 6 bit fraction */ | ||
436 | dig_rf_freq = rf_freq / MHz; | ||
437 | |||
438 | temp = rf_freq % MHz; | ||
439 | |||
440 | for (i = 0; i < 6; i++) { | ||
441 | dig_rf_freq <<= 1; | ||
442 | frac_divider /= 2; | ||
443 | if (temp > frac_divider) { | ||
444 | temp -= frac_divider; | ||
445 | dig_rf_freq++; | ||
446 | } | ||
447 | } | ||
448 | |||
449 | /* add to have shift center point by 7.8124 kHz */ | ||
450 | if (temp > 7812) | ||
451 | dig_rf_freq++; | ||
452 | |||
453 | set_reg_bits(state->tab_rftune, 0x0d, 0xff, (u8) dig_rf_freq); | ||
454 | set_reg_bits(state->tab_rftune, 0x0e, 0xff, (u8) (dig_rf_freq >> 8)); | ||
455 | |||
456 | if (rf_freq >= 333000000) | ||
457 | set_reg_bits(state->tab_rftune, 0x80, 0x40, 0x40); | ||
458 | |||
459 | return state->tab_rftune; | ||
460 | } | ||
461 | |||
462 | /* ------------------------------------------------------------------------- */ | ||
463 | |||
464 | static int mxl5007t_write_reg(struct mxl5007t_state *state, u8 reg, u8 val) | ||
465 | { | ||
466 | u8 buf[] = { reg, val }; | ||
467 | struct i2c_msg msg = { .addr = state->i2c_props.addr, .flags = 0, | ||
468 | .buf = buf, .len = 2 }; | ||
469 | int ret; | ||
470 | |||
471 | ret = i2c_transfer(state->i2c_props.adap, &msg, 1); | ||
472 | if (ret != 1) { | ||
473 | mxl_err("failed!"); | ||
474 | return -EREMOTEIO; | ||
475 | } | ||
476 | return 0; | ||
477 | } | ||
478 | |||
479 | static int mxl5007t_write_regs(struct mxl5007t_state *state, | ||
480 | struct reg_pair_t *reg_pair) | ||
481 | { | ||
482 | unsigned int i = 0; | ||
483 | int ret = 0; | ||
484 | |||
485 | while ((ret == 0) && (reg_pair[i].reg || reg_pair[i].val)) { | ||
486 | ret = mxl5007t_write_reg(state, | ||
487 | reg_pair[i].reg, reg_pair[i].val); | ||
488 | i++; | ||
489 | } | ||
490 | return ret; | ||
491 | } | ||
492 | |||
493 | static int mxl5007t_read_reg(struct mxl5007t_state *state, u8 reg, u8 *val) | ||
494 | { | ||
495 | u8 buf[2] = { 0xfb, reg }; | ||
496 | struct i2c_msg msg[] = { | ||
497 | { .addr = state->i2c_props.addr, .flags = 0, | ||
498 | .buf = buf, .len = 2 }, | ||
499 | { .addr = state->i2c_props.addr, .flags = I2C_M_RD, | ||
500 | .buf = val, .len = 1 }, | ||
501 | }; | ||
502 | int ret; | ||
503 | |||
504 | ret = i2c_transfer(state->i2c_props.adap, msg, 2); | ||
505 | if (ret != 2) { | ||
506 | mxl_err("failed!"); | ||
507 | return -EREMOTEIO; | ||
508 | } | ||
509 | return 0; | ||
510 | } | ||
511 | |||
512 | static int mxl5007t_soft_reset(struct mxl5007t_state *state) | ||
513 | { | ||
514 | u8 d = 0xff; | ||
515 | struct i2c_msg msg = { | ||
516 | .addr = state->i2c_props.addr, .flags = 0, | ||
517 | .buf = &d, .len = 1 | ||
518 | }; | ||
519 | int ret = i2c_transfer(state->i2c_props.adap, &msg, 1); | ||
520 | |||
521 | if (ret != 1) { | ||
522 | mxl_err("failed!"); | ||
523 | return -EREMOTEIO; | ||
524 | } | ||
525 | return 0; | ||
526 | } | ||
527 | |||
528 | static int mxl5007t_tuner_init(struct mxl5007t_state *state, | ||
529 | enum mxl5007t_mode mode) | ||
530 | { | ||
531 | struct reg_pair_t *init_regs; | ||
532 | int ret; | ||
533 | |||
534 | ret = mxl5007t_soft_reset(state); | ||
535 | if (mxl_fail(ret)) | ||
536 | goto fail; | ||
537 | |||
538 | /* calculate initialization reg array */ | ||
539 | init_regs = mxl5007t_calc_init_regs(state, mode); | ||
540 | |||
541 | ret = mxl5007t_write_regs(state, init_regs); | ||
542 | if (mxl_fail(ret)) | ||
543 | goto fail; | ||
544 | mdelay(1); | ||
545 | fail: | ||
546 | return ret; | ||
547 | } | ||
548 | |||
549 | static int mxl5007t_tuner_rf_tune(struct mxl5007t_state *state, u32 rf_freq_hz, | ||
550 | enum mxl5007t_bw_mhz bw) | ||
551 | { | ||
552 | struct reg_pair_t *rf_tune_regs; | ||
553 | int ret; | ||
554 | |||
555 | /* calculate channel change reg array */ | ||
556 | rf_tune_regs = mxl5007t_calc_rf_tune_regs(state, rf_freq_hz, bw); | ||
557 | |||
558 | ret = mxl5007t_write_regs(state, rf_tune_regs); | ||
559 | if (mxl_fail(ret)) | ||
560 | goto fail; | ||
561 | msleep(3); | ||
562 | fail: | ||
563 | return ret; | ||
564 | } | ||
565 | |||
566 | /* ------------------------------------------------------------------------- */ | ||
567 | |||
568 | static int mxl5007t_synth_lock_status(struct mxl5007t_state *state, | ||
569 | int *rf_locked, int *ref_locked) | ||
570 | { | ||
571 | u8 d; | ||
572 | int ret; | ||
573 | |||
574 | *rf_locked = 0; | ||
575 | *ref_locked = 0; | ||
576 | |||
577 | ret = mxl5007t_read_reg(state, 0xd8, &d); | ||
578 | if (mxl_fail(ret)) | ||
579 | goto fail; | ||
580 | |||
581 | if ((d & 0x0c) == 0x0c) | ||
582 | *rf_locked = 1; | ||
583 | |||
584 | if ((d & 0x03) == 0x03) | ||
585 | *ref_locked = 1; | ||
586 | fail: | ||
587 | return ret; | ||
588 | } | ||
589 | |||
590 | /* ------------------------------------------------------------------------- */ | ||
591 | |||
592 | static int mxl5007t_get_status(struct dvb_frontend *fe, u32 *status) | ||
593 | { | ||
594 | struct mxl5007t_state *state = fe->tuner_priv; | ||
595 | int rf_locked, ref_locked, ret; | ||
596 | |||
597 | *status = 0; | ||
598 | |||
599 | if (fe->ops.i2c_gate_ctrl) | ||
600 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
601 | |||
602 | ret = mxl5007t_synth_lock_status(state, &rf_locked, &ref_locked); | ||
603 | if (mxl_fail(ret)) | ||
604 | goto fail; | ||
605 | mxl_debug("%s%s", rf_locked ? "rf locked " : "", | ||
606 | ref_locked ? "ref locked" : ""); | ||
607 | |||
608 | if ((rf_locked) || (ref_locked)) | ||
609 | *status |= TUNER_STATUS_LOCKED; | ||
610 | fail: | ||
611 | if (fe->ops.i2c_gate_ctrl) | ||
612 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
613 | |||
614 | return ret; | ||
615 | } | ||
616 | |||
617 | /* ------------------------------------------------------------------------- */ | ||
618 | |||
619 | static int mxl5007t_set_params(struct dvb_frontend *fe) | ||
620 | { | ||
621 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
622 | u32 delsys = c->delivery_system; | ||
623 | struct mxl5007t_state *state = fe->tuner_priv; | ||
624 | enum mxl5007t_bw_mhz bw; | ||
625 | enum mxl5007t_mode mode; | ||
626 | int ret; | ||
627 | u32 freq = c->frequency; | ||
628 | |||
629 | switch (delsys) { | ||
630 | case SYS_ATSC: | ||
631 | mode = MxL_MODE_ATSC; | ||
632 | bw = MxL_BW_6MHz; | ||
633 | break; | ||
634 | case SYS_DVBC_ANNEX_B: | ||
635 | mode = MxL_MODE_CABLE; | ||
636 | bw = MxL_BW_6MHz; | ||
637 | break; | ||
638 | case SYS_DVBT: | ||
639 | case SYS_DVBT2: | ||
640 | mode = MxL_MODE_DVBT; | ||
641 | switch (c->bandwidth_hz) { | ||
642 | case 6000000: | ||
643 | bw = MxL_BW_6MHz; | ||
644 | break; | ||
645 | case 7000000: | ||
646 | bw = MxL_BW_7MHz; | ||
647 | break; | ||
648 | case 8000000: | ||
649 | bw = MxL_BW_8MHz; | ||
650 | break; | ||
651 | default: | ||
652 | return -EINVAL; | ||
653 | } | ||
654 | break; | ||
655 | default: | ||
656 | mxl_err("modulation type not supported!"); | ||
657 | return -EINVAL; | ||
658 | } | ||
659 | |||
660 | if (fe->ops.i2c_gate_ctrl) | ||
661 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
662 | |||
663 | mutex_lock(&state->lock); | ||
664 | |||
665 | ret = mxl5007t_tuner_init(state, mode); | ||
666 | if (mxl_fail(ret)) | ||
667 | goto fail; | ||
668 | |||
669 | ret = mxl5007t_tuner_rf_tune(state, freq, bw); | ||
670 | if (mxl_fail(ret)) | ||
671 | goto fail; | ||
672 | |||
673 | state->frequency = freq; | ||
674 | state->bandwidth = c->bandwidth_hz; | ||
675 | fail: | ||
676 | mutex_unlock(&state->lock); | ||
677 | |||
678 | if (fe->ops.i2c_gate_ctrl) | ||
679 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
680 | |||
681 | return ret; | ||
682 | } | ||
683 | |||
684 | /* ------------------------------------------------------------------------- */ | ||
685 | |||
686 | static int mxl5007t_init(struct dvb_frontend *fe) | ||
687 | { | ||
688 | struct mxl5007t_state *state = fe->tuner_priv; | ||
689 | int ret; | ||
690 | |||
691 | if (fe->ops.i2c_gate_ctrl) | ||
692 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
693 | |||
694 | /* wake from standby */ | ||
695 | ret = mxl5007t_write_reg(state, 0x01, 0x01); | ||
696 | mxl_fail(ret); | ||
697 | |||
698 | if (fe->ops.i2c_gate_ctrl) | ||
699 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
700 | |||
701 | return ret; | ||
702 | } | ||
703 | |||
704 | static int mxl5007t_sleep(struct dvb_frontend *fe) | ||
705 | { | ||
706 | struct mxl5007t_state *state = fe->tuner_priv; | ||
707 | int ret; | ||
708 | |||
709 | if (fe->ops.i2c_gate_ctrl) | ||
710 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
711 | |||
712 | /* enter standby mode */ | ||
713 | ret = mxl5007t_write_reg(state, 0x01, 0x00); | ||
714 | mxl_fail(ret); | ||
715 | ret = mxl5007t_write_reg(state, 0x0f, 0x00); | ||
716 | mxl_fail(ret); | ||
717 | |||
718 | if (fe->ops.i2c_gate_ctrl) | ||
719 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
720 | |||
721 | return ret; | ||
722 | } | ||
723 | |||
724 | /* ------------------------------------------------------------------------- */ | ||
725 | |||
726 | static int mxl5007t_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
727 | { | ||
728 | struct mxl5007t_state *state = fe->tuner_priv; | ||
729 | *frequency = state->frequency; | ||
730 | return 0; | ||
731 | } | ||
732 | |||
733 | static int mxl5007t_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) | ||
734 | { | ||
735 | struct mxl5007t_state *state = fe->tuner_priv; | ||
736 | *bandwidth = state->bandwidth; | ||
737 | return 0; | ||
738 | } | ||
739 | |||
740 | static int mxl5007t_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
741 | { | ||
742 | struct mxl5007t_state *state = fe->tuner_priv; | ||
743 | |||
744 | *frequency = 0; | ||
745 | |||
746 | switch (state->if_freq) { | ||
747 | case MxL_IF_4_MHZ: | ||
748 | *frequency = 4000000; | ||
749 | break; | ||
750 | case MxL_IF_4_5_MHZ: | ||
751 | *frequency = 4500000; | ||
752 | break; | ||
753 | case MxL_IF_4_57_MHZ: | ||
754 | *frequency = 4570000; | ||
755 | break; | ||
756 | case MxL_IF_5_MHZ: | ||
757 | *frequency = 5000000; | ||
758 | break; | ||
759 | case MxL_IF_5_38_MHZ: | ||
760 | *frequency = 5380000; | ||
761 | break; | ||
762 | case MxL_IF_6_MHZ: | ||
763 | *frequency = 6000000; | ||
764 | break; | ||
765 | case MxL_IF_6_28_MHZ: | ||
766 | *frequency = 6280000; | ||
767 | break; | ||
768 | case MxL_IF_9_1915_MHZ: | ||
769 | *frequency = 9191500; | ||
770 | break; | ||
771 | case MxL_IF_35_25_MHZ: | ||
772 | *frequency = 35250000; | ||
773 | break; | ||
774 | case MxL_IF_36_15_MHZ: | ||
775 | *frequency = 36150000; | ||
776 | break; | ||
777 | case MxL_IF_44_MHZ: | ||
778 | *frequency = 44000000; | ||
779 | break; | ||
780 | } | ||
781 | return 0; | ||
782 | } | ||
783 | |||
784 | static int mxl5007t_release(struct dvb_frontend *fe) | ||
785 | { | ||
786 | struct mxl5007t_state *state = fe->tuner_priv; | ||
787 | |||
788 | mutex_lock(&mxl5007t_list_mutex); | ||
789 | |||
790 | if (state) | ||
791 | hybrid_tuner_release_state(state); | ||
792 | |||
793 | mutex_unlock(&mxl5007t_list_mutex); | ||
794 | |||
795 | fe->tuner_priv = NULL; | ||
796 | |||
797 | return 0; | ||
798 | } | ||
799 | |||
800 | /* ------------------------------------------------------------------------- */ | ||
801 | |||
802 | static struct dvb_tuner_ops mxl5007t_tuner_ops = { | ||
803 | .info = { | ||
804 | .name = "MaxLinear MxL5007T", | ||
805 | }, | ||
806 | .init = mxl5007t_init, | ||
807 | .sleep = mxl5007t_sleep, | ||
808 | .set_params = mxl5007t_set_params, | ||
809 | .get_status = mxl5007t_get_status, | ||
810 | .get_frequency = mxl5007t_get_frequency, | ||
811 | .get_bandwidth = mxl5007t_get_bandwidth, | ||
812 | .release = mxl5007t_release, | ||
813 | .get_if_frequency = mxl5007t_get_if_frequency, | ||
814 | }; | ||
815 | |||
816 | static int mxl5007t_get_chip_id(struct mxl5007t_state *state) | ||
817 | { | ||
818 | char *name; | ||
819 | int ret; | ||
820 | u8 id; | ||
821 | |||
822 | ret = mxl5007t_read_reg(state, 0xd9, &id); | ||
823 | if (mxl_fail(ret)) | ||
824 | goto fail; | ||
825 | |||
826 | switch (id) { | ||
827 | case MxL_5007_V1_F1: | ||
828 | name = "MxL5007.v1.f1"; | ||
829 | break; | ||
830 | case MxL_5007_V1_F2: | ||
831 | name = "MxL5007.v1.f2"; | ||
832 | break; | ||
833 | case MxL_5007_V2_100_F1: | ||
834 | name = "MxL5007.v2.100.f1"; | ||
835 | break; | ||
836 | case MxL_5007_V2_100_F2: | ||
837 | name = "MxL5007.v2.100.f2"; | ||
838 | break; | ||
839 | case MxL_5007_V2_200_F1: | ||
840 | name = "MxL5007.v2.200.f1"; | ||
841 | break; | ||
842 | case MxL_5007_V2_200_F2: | ||
843 | name = "MxL5007.v2.200.f2"; | ||
844 | break; | ||
845 | case MxL_5007_V4: | ||
846 | name = "MxL5007T.v4"; | ||
847 | break; | ||
848 | default: | ||
849 | name = "MxL5007T"; | ||
850 | printk(KERN_WARNING "%s: unknown rev (%02x)\n", __func__, id); | ||
851 | id = MxL_UNKNOWN_ID; | ||
852 | } | ||
853 | state->chip_id = id; | ||
854 | mxl_info("%s detected @ %d-%04x", name, | ||
855 | i2c_adapter_id(state->i2c_props.adap), | ||
856 | state->i2c_props.addr); | ||
857 | return 0; | ||
858 | fail: | ||
859 | mxl_warn("unable to identify device @ %d-%04x", | ||
860 | i2c_adapter_id(state->i2c_props.adap), | ||
861 | state->i2c_props.addr); | ||
862 | |||
863 | state->chip_id = MxL_UNKNOWN_ID; | ||
864 | return ret; | ||
865 | } | ||
866 | |||
867 | struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, | ||
868 | struct i2c_adapter *i2c, u8 addr, | ||
869 | struct mxl5007t_config *cfg) | ||
870 | { | ||
871 | struct mxl5007t_state *state = NULL; | ||
872 | int instance, ret; | ||
873 | |||
874 | mutex_lock(&mxl5007t_list_mutex); | ||
875 | instance = hybrid_tuner_request_state(struct mxl5007t_state, state, | ||
876 | hybrid_tuner_instance_list, | ||
877 | i2c, addr, "mxl5007t"); | ||
878 | switch (instance) { | ||
879 | case 0: | ||
880 | goto fail; | ||
881 | case 1: | ||
882 | /* new tuner instance */ | ||
883 | state->config = cfg; | ||
884 | |||
885 | mutex_init(&state->lock); | ||
886 | |||
887 | if (fe->ops.i2c_gate_ctrl) | ||
888 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
889 | |||
890 | ret = mxl5007t_get_chip_id(state); | ||
891 | |||
892 | if (fe->ops.i2c_gate_ctrl) | ||
893 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
894 | |||
895 | /* check return value of mxl5007t_get_chip_id */ | ||
896 | if (mxl_fail(ret)) | ||
897 | goto fail; | ||
898 | break; | ||
899 | default: | ||
900 | /* existing tuner instance */ | ||
901 | break; | ||
902 | } | ||
903 | fe->tuner_priv = state; | ||
904 | mutex_unlock(&mxl5007t_list_mutex); | ||
905 | |||
906 | memcpy(&fe->ops.tuner_ops, &mxl5007t_tuner_ops, | ||
907 | sizeof(struct dvb_tuner_ops)); | ||
908 | |||
909 | return fe; | ||
910 | fail: | ||
911 | mutex_unlock(&mxl5007t_list_mutex); | ||
912 | |||
913 | mxl5007t_release(fe); | ||
914 | return NULL; | ||
915 | } | ||
916 | EXPORT_SYMBOL_GPL(mxl5007t_attach); | ||
917 | MODULE_DESCRIPTION("MaxLinear MxL5007T Silicon IC tuner driver"); | ||
918 | MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>"); | ||
919 | MODULE_LICENSE("GPL"); | ||
920 | MODULE_VERSION("0.2"); | ||
921 | |||
922 | /* | ||
923 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
924 | * --------------------------------------------------------------------------- | ||
925 | * Local variables: | ||
926 | * c-basic-offset: 8 | ||
927 | * End: | ||
928 | */ | ||
diff --git a/drivers/media/tuners/mxl5007t.h b/drivers/media/tuners/mxl5007t.h new file mode 100644 index 000000000000..aa3eea0b5262 --- /dev/null +++ b/drivers/media/tuners/mxl5007t.h | |||
@@ -0,0 +1,104 @@ | |||
1 | /* | ||
2 | * mxl5007t.h - driver for the MaxLinear MxL5007T silicon tuner | ||
3 | * | ||
4 | * Copyright (C) 2008 Michael Krufky <mkrufky@linuxtv.org> | ||
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 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef __MXL5007T_H__ | ||
22 | #define __MXL5007T_H__ | ||
23 | |||
24 | #include "dvb_frontend.h" | ||
25 | |||
26 | /* ------------------------------------------------------------------------- */ | ||
27 | |||
28 | enum mxl5007t_if_freq { | ||
29 | MxL_IF_4_MHZ, /* 4000000 */ | ||
30 | MxL_IF_4_5_MHZ, /* 4500000 */ | ||
31 | MxL_IF_4_57_MHZ, /* 4570000 */ | ||
32 | MxL_IF_5_MHZ, /* 5000000 */ | ||
33 | MxL_IF_5_38_MHZ, /* 5380000 */ | ||
34 | MxL_IF_6_MHZ, /* 6000000 */ | ||
35 | MxL_IF_6_28_MHZ, /* 6280000 */ | ||
36 | MxL_IF_9_1915_MHZ, /* 9191500 */ | ||
37 | MxL_IF_35_25_MHZ, /* 35250000 */ | ||
38 | MxL_IF_36_15_MHZ, /* 36150000 */ | ||
39 | MxL_IF_44_MHZ, /* 44000000 */ | ||
40 | }; | ||
41 | |||
42 | enum mxl5007t_xtal_freq { | ||
43 | MxL_XTAL_16_MHZ, /* 16000000 */ | ||
44 | MxL_XTAL_20_MHZ, /* 20000000 */ | ||
45 | MxL_XTAL_20_25_MHZ, /* 20250000 */ | ||
46 | MxL_XTAL_20_48_MHZ, /* 20480000 */ | ||
47 | MxL_XTAL_24_MHZ, /* 24000000 */ | ||
48 | MxL_XTAL_25_MHZ, /* 25000000 */ | ||
49 | MxL_XTAL_25_14_MHZ, /* 25140000 */ | ||
50 | MxL_XTAL_27_MHZ, /* 27000000 */ | ||
51 | MxL_XTAL_28_8_MHZ, /* 28800000 */ | ||
52 | MxL_XTAL_32_MHZ, /* 32000000 */ | ||
53 | MxL_XTAL_40_MHZ, /* 40000000 */ | ||
54 | MxL_XTAL_44_MHZ, /* 44000000 */ | ||
55 | MxL_XTAL_48_MHZ, /* 48000000 */ | ||
56 | MxL_XTAL_49_3811_MHZ, /* 49381100 */ | ||
57 | }; | ||
58 | |||
59 | enum mxl5007t_clkout_amp { | ||
60 | MxL_CLKOUT_AMP_0_94V = 0, | ||
61 | MxL_CLKOUT_AMP_0_53V = 1, | ||
62 | MxL_CLKOUT_AMP_0_37V = 2, | ||
63 | MxL_CLKOUT_AMP_0_28V = 3, | ||
64 | MxL_CLKOUT_AMP_0_23V = 4, | ||
65 | MxL_CLKOUT_AMP_0_20V = 5, | ||
66 | MxL_CLKOUT_AMP_0_17V = 6, | ||
67 | MxL_CLKOUT_AMP_0_15V = 7, | ||
68 | }; | ||
69 | |||
70 | struct mxl5007t_config { | ||
71 | s32 if_diff_out_level; | ||
72 | enum mxl5007t_clkout_amp clk_out_amp; | ||
73 | enum mxl5007t_xtal_freq xtal_freq_hz; | ||
74 | enum mxl5007t_if_freq if_freq_hz; | ||
75 | unsigned int invert_if:1; | ||
76 | unsigned int loop_thru_enable:1; | ||
77 | unsigned int clk_out_enable:1; | ||
78 | }; | ||
79 | |||
80 | #if defined(CONFIG_MEDIA_TUNER_MXL5007T) || (defined(CONFIG_MEDIA_TUNER_MXL5007T_MODULE) && defined(MODULE)) | ||
81 | extern struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, | ||
82 | struct i2c_adapter *i2c, u8 addr, | ||
83 | struct mxl5007t_config *cfg); | ||
84 | #else | ||
85 | static inline struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, | ||
86 | struct i2c_adapter *i2c, | ||
87 | u8 addr, | ||
88 | struct mxl5007t_config *cfg) | ||
89 | { | ||
90 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
91 | return NULL; | ||
92 | } | ||
93 | #endif | ||
94 | |||
95 | #endif /* __MXL5007T_H__ */ | ||
96 | |||
97 | /* | ||
98 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
99 | * --------------------------------------------------------------------------- | ||
100 | * Local variables: | ||
101 | * c-basic-offset: 8 | ||
102 | * End: | ||
103 | */ | ||
104 | |||
diff --git a/drivers/media/tuners/qt1010.c b/drivers/media/tuners/qt1010.c new file mode 100644 index 000000000000..bdc39e11030e --- /dev/null +++ b/drivers/media/tuners/qt1010.c | |||
@@ -0,0 +1,480 @@ | |||
1 | /* | ||
2 | * Driver for Quantek QT1010 silicon tuner | ||
3 | * | ||
4 | * Copyright (C) 2006 Antti Palosaari <crope@iki.fi> | ||
5 | * Aapo Tahkola <aet@rasterburn.org> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
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 | #include "qt1010.h" | ||
22 | #include "qt1010_priv.h" | ||
23 | |||
24 | static int debug; | ||
25 | module_param(debug, int, 0644); | ||
26 | MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); | ||
27 | |||
28 | #define dprintk(args...) \ | ||
29 | do { \ | ||
30 | if (debug) printk(KERN_DEBUG "QT1010: " args); \ | ||
31 | } while (0) | ||
32 | |||
33 | /* read single register */ | ||
34 | static int qt1010_readreg(struct qt1010_priv *priv, u8 reg, u8 *val) | ||
35 | { | ||
36 | struct i2c_msg msg[2] = { | ||
37 | { .addr = priv->cfg->i2c_address, | ||
38 | .flags = 0, .buf = ®, .len = 1 }, | ||
39 | { .addr = priv->cfg->i2c_address, | ||
40 | .flags = I2C_M_RD, .buf = val, .len = 1 }, | ||
41 | }; | ||
42 | |||
43 | if (i2c_transfer(priv->i2c, msg, 2) != 2) { | ||
44 | printk(KERN_WARNING "qt1010 I2C read failed\n"); | ||
45 | return -EREMOTEIO; | ||
46 | } | ||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | /* write single register */ | ||
51 | static int qt1010_writereg(struct qt1010_priv *priv, u8 reg, u8 val) | ||
52 | { | ||
53 | u8 buf[2] = { reg, val }; | ||
54 | struct i2c_msg msg = { .addr = priv->cfg->i2c_address, | ||
55 | .flags = 0, .buf = buf, .len = 2 }; | ||
56 | |||
57 | if (i2c_transfer(priv->i2c, &msg, 1) != 1) { | ||
58 | printk(KERN_WARNING "qt1010 I2C write failed\n"); | ||
59 | return -EREMOTEIO; | ||
60 | } | ||
61 | return 0; | ||
62 | } | ||
63 | |||
64 | /* dump all registers */ | ||
65 | static void qt1010_dump_regs(struct qt1010_priv *priv) | ||
66 | { | ||
67 | u8 reg, val; | ||
68 | |||
69 | for (reg = 0; ; reg++) { | ||
70 | if (reg % 16 == 0) { | ||
71 | if (reg) | ||
72 | printk(KERN_CONT "\n"); | ||
73 | printk(KERN_DEBUG "%02x:", reg); | ||
74 | } | ||
75 | if (qt1010_readreg(priv, reg, &val) == 0) | ||
76 | printk(KERN_CONT " %02x", val); | ||
77 | else | ||
78 | printk(KERN_CONT " --"); | ||
79 | if (reg == 0x2f) | ||
80 | break; | ||
81 | } | ||
82 | printk(KERN_CONT "\n"); | ||
83 | } | ||
84 | |||
85 | static int qt1010_set_params(struct dvb_frontend *fe) | ||
86 | { | ||
87 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
88 | struct qt1010_priv *priv; | ||
89 | int err; | ||
90 | u32 freq, div, mod1, mod2; | ||
91 | u8 i, tmpval, reg05; | ||
92 | qt1010_i2c_oper_t rd[48] = { | ||
93 | { QT1010_WR, 0x01, 0x80 }, | ||
94 | { QT1010_WR, 0x02, 0x3f }, | ||
95 | { QT1010_WR, 0x05, 0xff }, /* 02 c write */ | ||
96 | { QT1010_WR, 0x06, 0x44 }, | ||
97 | { QT1010_WR, 0x07, 0xff }, /* 04 c write */ | ||
98 | { QT1010_WR, 0x08, 0x08 }, | ||
99 | { QT1010_WR, 0x09, 0xff }, /* 06 c write */ | ||
100 | { QT1010_WR, 0x0a, 0xff }, /* 07 c write */ | ||
101 | { QT1010_WR, 0x0b, 0xff }, /* 08 c write */ | ||
102 | { QT1010_WR, 0x0c, 0xe1 }, | ||
103 | { QT1010_WR, 0x1a, 0xff }, /* 10 c write */ | ||
104 | { QT1010_WR, 0x1b, 0x00 }, | ||
105 | { QT1010_WR, 0x1c, 0x89 }, | ||
106 | { QT1010_WR, 0x11, 0xff }, /* 13 c write */ | ||
107 | { QT1010_WR, 0x12, 0xff }, /* 14 c write */ | ||
108 | { QT1010_WR, 0x22, 0xff }, /* 15 c write */ | ||
109 | { QT1010_WR, 0x1e, 0x00 }, | ||
110 | { QT1010_WR, 0x1e, 0xd0 }, | ||
111 | { QT1010_RD, 0x22, 0xff }, /* 16 c read */ | ||
112 | { QT1010_WR, 0x1e, 0x00 }, | ||
113 | { QT1010_RD, 0x05, 0xff }, /* 20 c read */ | ||
114 | { QT1010_RD, 0x22, 0xff }, /* 21 c read */ | ||
115 | { QT1010_WR, 0x23, 0xd0 }, | ||
116 | { QT1010_WR, 0x1e, 0x00 }, | ||
117 | { QT1010_WR, 0x1e, 0xe0 }, | ||
118 | { QT1010_RD, 0x23, 0xff }, /* 25 c read */ | ||
119 | { QT1010_RD, 0x23, 0xff }, /* 26 c read */ | ||
120 | { QT1010_WR, 0x1e, 0x00 }, | ||
121 | { QT1010_WR, 0x24, 0xd0 }, | ||
122 | { QT1010_WR, 0x1e, 0x00 }, | ||
123 | { QT1010_WR, 0x1e, 0xf0 }, | ||
124 | { QT1010_RD, 0x24, 0xff }, /* 31 c read */ | ||
125 | { QT1010_WR, 0x1e, 0x00 }, | ||
126 | { QT1010_WR, 0x14, 0x7f }, | ||
127 | { QT1010_WR, 0x15, 0x7f }, | ||
128 | { QT1010_WR, 0x05, 0xff }, /* 35 c write */ | ||
129 | { QT1010_WR, 0x06, 0x00 }, | ||
130 | { QT1010_WR, 0x15, 0x1f }, | ||
131 | { QT1010_WR, 0x16, 0xff }, | ||
132 | { QT1010_WR, 0x18, 0xff }, | ||
133 | { QT1010_WR, 0x1f, 0xff }, /* 40 c write */ | ||
134 | { QT1010_WR, 0x20, 0xff }, /* 41 c write */ | ||
135 | { QT1010_WR, 0x21, 0x53 }, | ||
136 | { QT1010_WR, 0x25, 0xff }, /* 43 c write */ | ||
137 | { QT1010_WR, 0x26, 0x15 }, | ||
138 | { QT1010_WR, 0x00, 0xff }, /* 45 c write */ | ||
139 | { QT1010_WR, 0x02, 0x00 }, | ||
140 | { QT1010_WR, 0x01, 0x00 } | ||
141 | }; | ||
142 | |||
143 | #define FREQ1 32000000 /* 32 MHz */ | ||
144 | #define FREQ2 4000000 /* 4 MHz Quartz oscillator in the stick? */ | ||
145 | |||
146 | priv = fe->tuner_priv; | ||
147 | freq = c->frequency; | ||
148 | div = (freq + QT1010_OFFSET) / QT1010_STEP; | ||
149 | freq = (div * QT1010_STEP) - QT1010_OFFSET; | ||
150 | mod1 = (freq + QT1010_OFFSET) % FREQ1; | ||
151 | mod2 = (freq + QT1010_OFFSET) % FREQ2; | ||
152 | priv->frequency = freq; | ||
153 | |||
154 | if (fe->ops.i2c_gate_ctrl) | ||
155 | fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ | ||
156 | |||
157 | /* reg 05 base value */ | ||
158 | if (freq < 290000000) reg05 = 0x14; /* 290 MHz */ | ||
159 | else if (freq < 610000000) reg05 = 0x34; /* 610 MHz */ | ||
160 | else if (freq < 802000000) reg05 = 0x54; /* 802 MHz */ | ||
161 | else reg05 = 0x74; | ||
162 | |||
163 | /* 0x5 */ | ||
164 | rd[2].val = reg05; | ||
165 | |||
166 | /* 07 - set frequency: 32 MHz scale */ | ||
167 | rd[4].val = (freq + QT1010_OFFSET) / FREQ1; | ||
168 | |||
169 | /* 09 - changes every 8/24 MHz */ | ||
170 | if (mod1 < 8000000) rd[6].val = 0x1d; | ||
171 | else rd[6].val = 0x1c; | ||
172 | |||
173 | /* 0a - set frequency: 4 MHz scale (max 28 MHz) */ | ||
174 | if (mod1 < 1*FREQ2) rd[7].val = 0x09; /* +0 MHz */ | ||
175 | else if (mod1 < 2*FREQ2) rd[7].val = 0x08; /* +4 MHz */ | ||
176 | else if (mod1 < 3*FREQ2) rd[7].val = 0x0f; /* +8 MHz */ | ||
177 | else if (mod1 < 4*FREQ2) rd[7].val = 0x0e; /* +12 MHz */ | ||
178 | else if (mod1 < 5*FREQ2) rd[7].val = 0x0d; /* +16 MHz */ | ||
179 | else if (mod1 < 6*FREQ2) rd[7].val = 0x0c; /* +20 MHz */ | ||
180 | else if (mod1 < 7*FREQ2) rd[7].val = 0x0b; /* +24 MHz */ | ||
181 | else rd[7].val = 0x0a; /* +28 MHz */ | ||
182 | |||
183 | /* 0b - changes every 2/2 MHz */ | ||
184 | if (mod2 < 2000000) rd[8].val = 0x45; | ||
185 | else rd[8].val = 0x44; | ||
186 | |||
187 | /* 1a - set frequency: 125 kHz scale (max 3875 kHz)*/ | ||
188 | tmpval = 0x78; /* byte, overflows intentionally */ | ||
189 | rd[10].val = tmpval-((mod2/QT1010_STEP)*0x08); | ||
190 | |||
191 | /* 11 */ | ||
192 | rd[13].val = 0xfd; /* TODO: correct value calculation */ | ||
193 | |||
194 | /* 12 */ | ||
195 | rd[14].val = 0x91; /* TODO: correct value calculation */ | ||
196 | |||
197 | /* 22 */ | ||
198 | if (freq < 450000000) rd[15].val = 0xd0; /* 450 MHz */ | ||
199 | else if (freq < 482000000) rd[15].val = 0xd1; /* 482 MHz */ | ||
200 | else if (freq < 514000000) rd[15].val = 0xd4; /* 514 MHz */ | ||
201 | else if (freq < 546000000) rd[15].val = 0xd7; /* 546 MHz */ | ||
202 | else if (freq < 610000000) rd[15].val = 0xda; /* 610 MHz */ | ||
203 | else rd[15].val = 0xd0; | ||
204 | |||
205 | /* 05 */ | ||
206 | rd[35].val = (reg05 & 0xf0); | ||
207 | |||
208 | /* 1f */ | ||
209 | if (mod1 < 8000000) tmpval = 0x00; | ||
210 | else if (mod1 < 12000000) tmpval = 0x01; | ||
211 | else if (mod1 < 16000000) tmpval = 0x02; | ||
212 | else if (mod1 < 24000000) tmpval = 0x03; | ||
213 | else if (mod1 < 28000000) tmpval = 0x04; | ||
214 | else tmpval = 0x05; | ||
215 | rd[40].val = (priv->reg1f_init_val + 0x0e + tmpval); | ||
216 | |||
217 | /* 20 */ | ||
218 | if (mod1 < 8000000) tmpval = 0x00; | ||
219 | else if (mod1 < 12000000) tmpval = 0x01; | ||
220 | else if (mod1 < 20000000) tmpval = 0x02; | ||
221 | else if (mod1 < 24000000) tmpval = 0x03; | ||
222 | else if (mod1 < 28000000) tmpval = 0x04; | ||
223 | else tmpval = 0x05; | ||
224 | rd[41].val = (priv->reg20_init_val + 0x0d + tmpval); | ||
225 | |||
226 | /* 25 */ | ||
227 | rd[43].val = priv->reg25_init_val; | ||
228 | |||
229 | /* 00 */ | ||
230 | rd[45].val = 0x92; /* TODO: correct value calculation */ | ||
231 | |||
232 | dprintk("freq:%u 05:%02x 07:%02x 09:%02x 0a:%02x 0b:%02x " \ | ||
233 | "1a:%02x 11:%02x 12:%02x 22:%02x 05:%02x 1f:%02x " \ | ||
234 | "20:%02x 25:%02x 00:%02x", \ | ||
235 | freq, rd[2].val, rd[4].val, rd[6].val, rd[7].val, rd[8].val, \ | ||
236 | rd[10].val, rd[13].val, rd[14].val, rd[15].val, rd[35].val, \ | ||
237 | rd[40].val, rd[41].val, rd[43].val, rd[45].val); | ||
238 | |||
239 | for (i = 0; i < ARRAY_SIZE(rd); i++) { | ||
240 | if (rd[i].oper == QT1010_WR) { | ||
241 | err = qt1010_writereg(priv, rd[i].reg, rd[i].val); | ||
242 | } else { /* read is required to proper locking */ | ||
243 | err = qt1010_readreg(priv, rd[i].reg, &tmpval); | ||
244 | } | ||
245 | if (err) return err; | ||
246 | } | ||
247 | |||
248 | if (debug) | ||
249 | qt1010_dump_regs(priv); | ||
250 | |||
251 | if (fe->ops.i2c_gate_ctrl) | ||
252 | fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ | ||
253 | |||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | static int qt1010_init_meas1(struct qt1010_priv *priv, | ||
258 | u8 oper, u8 reg, u8 reg_init_val, u8 *retval) | ||
259 | { | ||
260 | u8 i, val1, val2; | ||
261 | int err; | ||
262 | |||
263 | qt1010_i2c_oper_t i2c_data[] = { | ||
264 | { QT1010_WR, reg, reg_init_val }, | ||
265 | { QT1010_WR, 0x1e, 0x00 }, | ||
266 | { QT1010_WR, 0x1e, oper }, | ||
267 | { QT1010_RD, reg, 0xff } | ||
268 | }; | ||
269 | |||
270 | for (i = 0; i < ARRAY_SIZE(i2c_data); i++) { | ||
271 | if (i2c_data[i].oper == QT1010_WR) { | ||
272 | err = qt1010_writereg(priv, i2c_data[i].reg, | ||
273 | i2c_data[i].val); | ||
274 | } else { | ||
275 | err = qt1010_readreg(priv, i2c_data[i].reg, &val2); | ||
276 | } | ||
277 | if (err) return err; | ||
278 | } | ||
279 | |||
280 | do { | ||
281 | val1 = val2; | ||
282 | err = qt1010_readreg(priv, reg, &val2); | ||
283 | if (err) return err; | ||
284 | dprintk("compare reg:%02x %02x %02x", reg, val1, val2); | ||
285 | } while (val1 != val2); | ||
286 | *retval = val1; | ||
287 | |||
288 | return qt1010_writereg(priv, 0x1e, 0x00); | ||
289 | } | ||
290 | |||
291 | static int qt1010_init_meas2(struct qt1010_priv *priv, | ||
292 | u8 reg_init_val, u8 *retval) | ||
293 | { | ||
294 | u8 i, val; | ||
295 | int err; | ||
296 | qt1010_i2c_oper_t i2c_data[] = { | ||
297 | { QT1010_WR, 0x07, reg_init_val }, | ||
298 | { QT1010_WR, 0x22, 0xd0 }, | ||
299 | { QT1010_WR, 0x1e, 0x00 }, | ||
300 | { QT1010_WR, 0x1e, 0xd0 }, | ||
301 | { QT1010_RD, 0x22, 0xff }, | ||
302 | { QT1010_WR, 0x1e, 0x00 }, | ||
303 | { QT1010_WR, 0x22, 0xff } | ||
304 | }; | ||
305 | for (i = 0; i < ARRAY_SIZE(i2c_data); i++) { | ||
306 | if (i2c_data[i].oper == QT1010_WR) { | ||
307 | err = qt1010_writereg(priv, i2c_data[i].reg, | ||
308 | i2c_data[i].val); | ||
309 | } else { | ||
310 | err = qt1010_readreg(priv, i2c_data[i].reg, &val); | ||
311 | } | ||
312 | if (err) return err; | ||
313 | } | ||
314 | *retval = val; | ||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | static int qt1010_init(struct dvb_frontend *fe) | ||
319 | { | ||
320 | struct qt1010_priv *priv = fe->tuner_priv; | ||
321 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
322 | int err = 0; | ||
323 | u8 i, tmpval, *valptr = NULL; | ||
324 | |||
325 | qt1010_i2c_oper_t i2c_data[] = { | ||
326 | { QT1010_WR, 0x01, 0x80 }, | ||
327 | { QT1010_WR, 0x0d, 0x84 }, | ||
328 | { QT1010_WR, 0x0e, 0xb7 }, | ||
329 | { QT1010_WR, 0x2a, 0x23 }, | ||
330 | { QT1010_WR, 0x2c, 0xdc }, | ||
331 | { QT1010_M1, 0x25, 0x40 }, /* get reg 25 init value */ | ||
332 | { QT1010_M1, 0x81, 0xff }, /* get reg 25 init value */ | ||
333 | { QT1010_WR, 0x2b, 0x70 }, | ||
334 | { QT1010_WR, 0x2a, 0x23 }, | ||
335 | { QT1010_M1, 0x26, 0x08 }, | ||
336 | { QT1010_M1, 0x82, 0xff }, | ||
337 | { QT1010_WR, 0x05, 0x14 }, | ||
338 | { QT1010_WR, 0x06, 0x44 }, | ||
339 | { QT1010_WR, 0x07, 0x28 }, | ||
340 | { QT1010_WR, 0x08, 0x0b }, | ||
341 | { QT1010_WR, 0x11, 0xfd }, | ||
342 | { QT1010_M1, 0x22, 0x0d }, | ||
343 | { QT1010_M1, 0xd0, 0xff }, | ||
344 | { QT1010_WR, 0x06, 0x40 }, | ||
345 | { QT1010_WR, 0x16, 0xf0 }, | ||
346 | { QT1010_WR, 0x02, 0x38 }, | ||
347 | { QT1010_WR, 0x03, 0x18 }, | ||
348 | { QT1010_WR, 0x20, 0xe0 }, | ||
349 | { QT1010_M1, 0x1f, 0x20 }, /* get reg 1f init value */ | ||
350 | { QT1010_M1, 0x84, 0xff }, /* get reg 1f init value */ | ||
351 | { QT1010_RD, 0x20, 0x20 }, /* get reg 20 init value */ | ||
352 | { QT1010_WR, 0x03, 0x19 }, | ||
353 | { QT1010_WR, 0x02, 0x3f }, | ||
354 | { QT1010_WR, 0x21, 0x53 }, | ||
355 | { QT1010_RD, 0x21, 0xff }, | ||
356 | { QT1010_WR, 0x11, 0xfd }, | ||
357 | { QT1010_WR, 0x05, 0x34 }, | ||
358 | { QT1010_WR, 0x06, 0x44 }, | ||
359 | { QT1010_WR, 0x08, 0x08 } | ||
360 | }; | ||
361 | |||
362 | if (fe->ops.i2c_gate_ctrl) | ||
363 | fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ | ||
364 | |||
365 | for (i = 0; i < ARRAY_SIZE(i2c_data); i++) { | ||
366 | switch (i2c_data[i].oper) { | ||
367 | case QT1010_WR: | ||
368 | err = qt1010_writereg(priv, i2c_data[i].reg, | ||
369 | i2c_data[i].val); | ||
370 | break; | ||
371 | case QT1010_RD: | ||
372 | if (i2c_data[i].val == 0x20) | ||
373 | valptr = &priv->reg20_init_val; | ||
374 | else | ||
375 | valptr = &tmpval; | ||
376 | err = qt1010_readreg(priv, i2c_data[i].reg, valptr); | ||
377 | break; | ||
378 | case QT1010_M1: | ||
379 | if (i2c_data[i].val == 0x25) | ||
380 | valptr = &priv->reg25_init_val; | ||
381 | else if (i2c_data[i].val == 0x1f) | ||
382 | valptr = &priv->reg1f_init_val; | ||
383 | else | ||
384 | valptr = &tmpval; | ||
385 | err = qt1010_init_meas1(priv, i2c_data[i+1].reg, | ||
386 | i2c_data[i].reg, | ||
387 | i2c_data[i].val, valptr); | ||
388 | i++; | ||
389 | break; | ||
390 | } | ||
391 | if (err) return err; | ||
392 | } | ||
393 | |||
394 | for (i = 0x31; i < 0x3a; i++) /* 0x31 - 0x39 */ | ||
395 | if ((err = qt1010_init_meas2(priv, i, &tmpval))) | ||
396 | return err; | ||
397 | |||
398 | c->frequency = 545000000; /* Sigmatek DVB-110 545000000 */ | ||
399 | /* MSI Megasky 580 GL861 533000000 */ | ||
400 | return qt1010_set_params(fe); | ||
401 | } | ||
402 | |||
403 | static int qt1010_release(struct dvb_frontend *fe) | ||
404 | { | ||
405 | kfree(fe->tuner_priv); | ||
406 | fe->tuner_priv = NULL; | ||
407 | return 0; | ||
408 | } | ||
409 | |||
410 | static int qt1010_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
411 | { | ||
412 | struct qt1010_priv *priv = fe->tuner_priv; | ||
413 | *frequency = priv->frequency; | ||
414 | return 0; | ||
415 | } | ||
416 | |||
417 | static int qt1010_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
418 | { | ||
419 | *frequency = 36125000; | ||
420 | return 0; | ||
421 | } | ||
422 | |||
423 | static const struct dvb_tuner_ops qt1010_tuner_ops = { | ||
424 | .info = { | ||
425 | .name = "Quantek QT1010", | ||
426 | .frequency_min = QT1010_MIN_FREQ, | ||
427 | .frequency_max = QT1010_MAX_FREQ, | ||
428 | .frequency_step = QT1010_STEP, | ||
429 | }, | ||
430 | |||
431 | .release = qt1010_release, | ||
432 | .init = qt1010_init, | ||
433 | /* TODO: implement sleep */ | ||
434 | |||
435 | .set_params = qt1010_set_params, | ||
436 | .get_frequency = qt1010_get_frequency, | ||
437 | .get_if_frequency = qt1010_get_if_frequency, | ||
438 | }; | ||
439 | |||
440 | struct dvb_frontend * qt1010_attach(struct dvb_frontend *fe, | ||
441 | struct i2c_adapter *i2c, | ||
442 | struct qt1010_config *cfg) | ||
443 | { | ||
444 | struct qt1010_priv *priv = NULL; | ||
445 | u8 id; | ||
446 | |||
447 | priv = kzalloc(sizeof(struct qt1010_priv), GFP_KERNEL); | ||
448 | if (priv == NULL) | ||
449 | return NULL; | ||
450 | |||
451 | priv->cfg = cfg; | ||
452 | priv->i2c = i2c; | ||
453 | |||
454 | if (fe->ops.i2c_gate_ctrl) | ||
455 | fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c_gate */ | ||
456 | |||
457 | |||
458 | /* Try to detect tuner chip. Probably this is not correct register. */ | ||
459 | if (qt1010_readreg(priv, 0x29, &id) != 0 || (id != 0x39)) { | ||
460 | kfree(priv); | ||
461 | return NULL; | ||
462 | } | ||
463 | |||
464 | if (fe->ops.i2c_gate_ctrl) | ||
465 | fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c_gate */ | ||
466 | |||
467 | printk(KERN_INFO "Quantek QT1010 successfully identified.\n"); | ||
468 | memcpy(&fe->ops.tuner_ops, &qt1010_tuner_ops, | ||
469 | sizeof(struct dvb_tuner_ops)); | ||
470 | |||
471 | fe->tuner_priv = priv; | ||
472 | return fe; | ||
473 | } | ||
474 | EXPORT_SYMBOL(qt1010_attach); | ||
475 | |||
476 | MODULE_DESCRIPTION("Quantek QT1010 silicon tuner driver"); | ||
477 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | ||
478 | MODULE_AUTHOR("Aapo Tahkola <aet@rasterburn.org>"); | ||
479 | MODULE_VERSION("0.1"); | ||
480 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/tuners/qt1010.h b/drivers/media/tuners/qt1010.h new file mode 100644 index 000000000000..807fb7b6146b --- /dev/null +++ b/drivers/media/tuners/qt1010.h | |||
@@ -0,0 +1,53 @@ | |||
1 | /* | ||
2 | * Driver for Quantek QT1010 silicon tuner | ||
3 | * | ||
4 | * Copyright (C) 2006 Antti Palosaari <crope@iki.fi> | ||
5 | * Aapo Tahkola <aet@rasterburn.org> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
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 QT1010_H | ||
23 | #define QT1010_H | ||
24 | |||
25 | #include "dvb_frontend.h" | ||
26 | |||
27 | struct qt1010_config { | ||
28 | u8 i2c_address; | ||
29 | }; | ||
30 | |||
31 | /** | ||
32 | * Attach a qt1010 tuner to the supplied frontend structure. | ||
33 | * | ||
34 | * @param fe frontend to attach to | ||
35 | * @param i2c i2c adapter to use | ||
36 | * @param cfg tuner hw based configuration | ||
37 | * @return fe pointer on success, NULL on failure | ||
38 | */ | ||
39 | #if defined(CONFIG_MEDIA_TUNER_QT1010) || (defined(CONFIG_MEDIA_TUNER_QT1010_MODULE) && defined(MODULE)) | ||
40 | extern struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe, | ||
41 | struct i2c_adapter *i2c, | ||
42 | struct qt1010_config *cfg); | ||
43 | #else | ||
44 | static inline struct dvb_frontend *qt1010_attach(struct dvb_frontend *fe, | ||
45 | struct i2c_adapter *i2c, | ||
46 | struct qt1010_config *cfg) | ||
47 | { | ||
48 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
49 | return NULL; | ||
50 | } | ||
51 | #endif // CONFIG_MEDIA_TUNER_QT1010 | ||
52 | |||
53 | #endif | ||
diff --git a/drivers/media/tuners/qt1010_priv.h b/drivers/media/tuners/qt1010_priv.h new file mode 100644 index 000000000000..2c42d3f01636 --- /dev/null +++ b/drivers/media/tuners/qt1010_priv.h | |||
@@ -0,0 +1,104 @@ | |||
1 | /* | ||
2 | * Driver for Quantek QT1010 silicon tuner | ||
3 | * | ||
4 | * Copyright (C) 2006 Antti Palosaari <crope@iki.fi> | ||
5 | * Aapo Tahkola <aet@rasterburn.org> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
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 QT1010_PRIV_H | ||
23 | #define QT1010_PRIV_H | ||
24 | |||
25 | /* | ||
26 | reg def meaning | ||
27 | === === ======= | ||
28 | 00 00 ? | ||
29 | 01 a0 ? operation start/stop; start=80, stop=00 | ||
30 | 02 00 ? | ||
31 | 03 19 ? | ||
32 | 04 00 ? | ||
33 | 05 00 ? maybe band selection | ||
34 | 06 00 ? | ||
35 | 07 2b set frequency: 32 MHz scale, n*32 MHz | ||
36 | 08 0b ? | ||
37 | 09 10 ? changes every 8/24 MHz; values 1d/1c | ||
38 | 0a 08 set frequency: 4 MHz scale, n*4 MHz | ||
39 | 0b 41 ? changes every 2/2 MHz; values 45/45 | ||
40 | 0c e1 ? | ||
41 | 0d 94 ? | ||
42 | 0e b6 ? | ||
43 | 0f 2c ? | ||
44 | 10 10 ? | ||
45 | 11 f1 ? maybe device specified adjustment | ||
46 | 12 11 ? maybe device specified adjustment | ||
47 | 13 3f ? | ||
48 | 14 1f ? | ||
49 | 15 3f ? | ||
50 | 16 ff ? | ||
51 | 17 ff ? | ||
52 | 18 f7 ? | ||
53 | 19 80 ? | ||
54 | 1a d0 set frequency: 125 kHz scale, n*125 kHz | ||
55 | 1b 00 ? | ||
56 | 1c 89 ? | ||
57 | 1d 00 ? | ||
58 | 1e 00 ? looks like operation register; write cmd here, read result from 1f-26 | ||
59 | 1f 20 ? chip initialization | ||
60 | 20 e0 ? chip initialization | ||
61 | 21 20 ? | ||
62 | 22 d0 ? | ||
63 | 23 d0 ? | ||
64 | 24 d0 ? | ||
65 | 25 40 ? chip initialization | ||
66 | 26 08 ? | ||
67 | 27 29 ? | ||
68 | 28 55 ? | ||
69 | 29 39 ? | ||
70 | 2a 13 ? | ||
71 | 2b 01 ? | ||
72 | 2c ea ? | ||
73 | 2d 00 ? | ||
74 | 2e 00 ? not used? | ||
75 | 2f 00 ? not used? | ||
76 | */ | ||
77 | |||
78 | #define QT1010_STEP 125000 /* 125 kHz used by Windows drivers, | ||
79 | hw could be more precise but we don't | ||
80 | know how to use */ | ||
81 | #define QT1010_MIN_FREQ 48000000 /* 48 MHz */ | ||
82 | #define QT1010_MAX_FREQ 860000000 /* 860 MHz */ | ||
83 | #define QT1010_OFFSET 1246000000 /* 1246 MHz */ | ||
84 | |||
85 | #define QT1010_WR 0 | ||
86 | #define QT1010_RD 1 | ||
87 | #define QT1010_M1 3 | ||
88 | |||
89 | typedef struct { | ||
90 | u8 oper, reg, val; | ||
91 | } qt1010_i2c_oper_t; | ||
92 | |||
93 | struct qt1010_priv { | ||
94 | struct qt1010_config *cfg; | ||
95 | struct i2c_adapter *i2c; | ||
96 | |||
97 | u8 reg1f_init_val; | ||
98 | u8 reg20_init_val; | ||
99 | u8 reg25_init_val; | ||
100 | |||
101 | u32 frequency; | ||
102 | }; | ||
103 | |||
104 | #endif | ||
diff --git a/drivers/media/tuners/tda18212.c b/drivers/media/tuners/tda18212.c new file mode 100644 index 000000000000..5d9f02842501 --- /dev/null +++ b/drivers/media/tuners/tda18212.c | |||
@@ -0,0 +1,319 @@ | |||
1 | /* | ||
2 | * NXP TDA18212HN silicon tuner driver | ||
3 | * | ||
4 | * Copyright (C) 2011 Antti Palosaari <crope@iki.fi> | ||
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 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #include "tda18212.h" | ||
22 | |||
23 | struct tda18212_priv { | ||
24 | struct tda18212_config *cfg; | ||
25 | struct i2c_adapter *i2c; | ||
26 | |||
27 | u32 if_frequency; | ||
28 | }; | ||
29 | |||
30 | /* write multiple registers */ | ||
31 | static int tda18212_wr_regs(struct tda18212_priv *priv, u8 reg, u8 *val, | ||
32 | int len) | ||
33 | { | ||
34 | int ret; | ||
35 | u8 buf[len+1]; | ||
36 | struct i2c_msg msg[1] = { | ||
37 | { | ||
38 | .addr = priv->cfg->i2c_address, | ||
39 | .flags = 0, | ||
40 | .len = sizeof(buf), | ||
41 | .buf = buf, | ||
42 | } | ||
43 | }; | ||
44 | |||
45 | buf[0] = reg; | ||
46 | memcpy(&buf[1], val, len); | ||
47 | |||
48 | ret = i2c_transfer(priv->i2c, msg, 1); | ||
49 | if (ret == 1) { | ||
50 | ret = 0; | ||
51 | } else { | ||
52 | dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d reg=%02x " \ | ||
53 | "len=%d\n", KBUILD_MODNAME, ret, reg, len); | ||
54 | ret = -EREMOTEIO; | ||
55 | } | ||
56 | return ret; | ||
57 | } | ||
58 | |||
59 | /* read multiple registers */ | ||
60 | static int tda18212_rd_regs(struct tda18212_priv *priv, u8 reg, u8 *val, | ||
61 | int len) | ||
62 | { | ||
63 | int ret; | ||
64 | u8 buf[len]; | ||
65 | struct i2c_msg msg[2] = { | ||
66 | { | ||
67 | .addr = priv->cfg->i2c_address, | ||
68 | .flags = 0, | ||
69 | .len = 1, | ||
70 | .buf = ®, | ||
71 | }, { | ||
72 | .addr = priv->cfg->i2c_address, | ||
73 | .flags = I2C_M_RD, | ||
74 | .len = sizeof(buf), | ||
75 | .buf = buf, | ||
76 | } | ||
77 | }; | ||
78 | |||
79 | ret = i2c_transfer(priv->i2c, msg, 2); | ||
80 | if (ret == 2) { | ||
81 | memcpy(val, buf, len); | ||
82 | ret = 0; | ||
83 | } else { | ||
84 | dev_warn(&priv->i2c->dev, "%s: i2c rd failed=%d reg=%02x " \ | ||
85 | "len=%d\n", KBUILD_MODNAME, ret, reg, len); | ||
86 | ret = -EREMOTEIO; | ||
87 | } | ||
88 | |||
89 | return ret; | ||
90 | } | ||
91 | |||
92 | /* write single register */ | ||
93 | static int tda18212_wr_reg(struct tda18212_priv *priv, u8 reg, u8 val) | ||
94 | { | ||
95 | return tda18212_wr_regs(priv, reg, &val, 1); | ||
96 | } | ||
97 | |||
98 | /* read single register */ | ||
99 | static int tda18212_rd_reg(struct tda18212_priv *priv, u8 reg, u8 *val) | ||
100 | { | ||
101 | return tda18212_rd_regs(priv, reg, val, 1); | ||
102 | } | ||
103 | |||
104 | #if 0 /* keep, useful when developing driver */ | ||
105 | static void tda18212_dump_regs(struct tda18212_priv *priv) | ||
106 | { | ||
107 | int i; | ||
108 | u8 buf[256]; | ||
109 | |||
110 | #define TDA18212_RD_LEN 32 | ||
111 | for (i = 0; i < sizeof(buf); i += TDA18212_RD_LEN) | ||
112 | tda18212_rd_regs(priv, i, &buf[i], TDA18212_RD_LEN); | ||
113 | |||
114 | print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 32, 1, buf, | ||
115 | sizeof(buf), true); | ||
116 | |||
117 | return; | ||
118 | } | ||
119 | #endif | ||
120 | |||
121 | static int tda18212_set_params(struct dvb_frontend *fe) | ||
122 | { | ||
123 | struct tda18212_priv *priv = fe->tuner_priv; | ||
124 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
125 | int ret, i; | ||
126 | u32 if_khz; | ||
127 | u8 buf[9]; | ||
128 | #define DVBT_6 0 | ||
129 | #define DVBT_7 1 | ||
130 | #define DVBT_8 2 | ||
131 | #define DVBT2_6 3 | ||
132 | #define DVBT2_7 4 | ||
133 | #define DVBT2_8 5 | ||
134 | #define DVBC_6 6 | ||
135 | #define DVBC_8 7 | ||
136 | static const u8 bw_params[][3] = { | ||
137 | /* reg: 0f 13 23 */ | ||
138 | [DVBT_6] = { 0xb3, 0x20, 0x03 }, | ||
139 | [DVBT_7] = { 0xb3, 0x31, 0x01 }, | ||
140 | [DVBT_8] = { 0xb3, 0x22, 0x01 }, | ||
141 | [DVBT2_6] = { 0xbc, 0x20, 0x03 }, | ||
142 | [DVBT2_7] = { 0xbc, 0x72, 0x03 }, | ||
143 | [DVBT2_8] = { 0xbc, 0x22, 0x01 }, | ||
144 | [DVBC_6] = { 0x92, 0x50, 0x03 }, | ||
145 | [DVBC_8] = { 0x92, 0x53, 0x03 }, | ||
146 | }; | ||
147 | |||
148 | dev_dbg(&priv->i2c->dev, | ||
149 | "%s: delivery_system=%d frequency=%d bandwidth_hz=%d\n", | ||
150 | __func__, c->delivery_system, c->frequency, | ||
151 | c->bandwidth_hz); | ||
152 | |||
153 | if (fe->ops.i2c_gate_ctrl) | ||
154 | fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ | ||
155 | |||
156 | switch (c->delivery_system) { | ||
157 | case SYS_DVBT: | ||
158 | switch (c->bandwidth_hz) { | ||
159 | case 6000000: | ||
160 | if_khz = priv->cfg->if_dvbt_6; | ||
161 | i = DVBT_6; | ||
162 | break; | ||
163 | case 7000000: | ||
164 | if_khz = priv->cfg->if_dvbt_7; | ||
165 | i = DVBT_7; | ||
166 | break; | ||
167 | case 8000000: | ||
168 | if_khz = priv->cfg->if_dvbt_8; | ||
169 | i = DVBT_8; | ||
170 | break; | ||
171 | default: | ||
172 | ret = -EINVAL; | ||
173 | goto error; | ||
174 | } | ||
175 | break; | ||
176 | case SYS_DVBT2: | ||
177 | switch (c->bandwidth_hz) { | ||
178 | case 6000000: | ||
179 | if_khz = priv->cfg->if_dvbt2_6; | ||
180 | i = DVBT2_6; | ||
181 | break; | ||
182 | case 7000000: | ||
183 | if_khz = priv->cfg->if_dvbt2_7; | ||
184 | i = DVBT2_7; | ||
185 | break; | ||
186 | case 8000000: | ||
187 | if_khz = priv->cfg->if_dvbt2_8; | ||
188 | i = DVBT2_8; | ||
189 | break; | ||
190 | default: | ||
191 | ret = -EINVAL; | ||
192 | goto error; | ||
193 | } | ||
194 | break; | ||
195 | case SYS_DVBC_ANNEX_A: | ||
196 | case SYS_DVBC_ANNEX_C: | ||
197 | if_khz = priv->cfg->if_dvbc; | ||
198 | i = DVBC_8; | ||
199 | break; | ||
200 | default: | ||
201 | ret = -EINVAL; | ||
202 | goto error; | ||
203 | } | ||
204 | |||
205 | ret = tda18212_wr_reg(priv, 0x23, bw_params[i][2]); | ||
206 | if (ret) | ||
207 | goto error; | ||
208 | |||
209 | ret = tda18212_wr_reg(priv, 0x06, 0x00); | ||
210 | if (ret) | ||
211 | goto error; | ||
212 | |||
213 | ret = tda18212_wr_reg(priv, 0x0f, bw_params[i][0]); | ||
214 | if (ret) | ||
215 | goto error; | ||
216 | |||
217 | buf[0] = 0x02; | ||
218 | buf[1] = bw_params[i][1]; | ||
219 | buf[2] = 0x03; /* default value */ | ||
220 | buf[3] = DIV_ROUND_CLOSEST(if_khz, 50); | ||
221 | buf[4] = ((c->frequency / 1000) >> 16) & 0xff; | ||
222 | buf[5] = ((c->frequency / 1000) >> 8) & 0xff; | ||
223 | buf[6] = ((c->frequency / 1000) >> 0) & 0xff; | ||
224 | buf[7] = 0xc1; | ||
225 | buf[8] = 0x01; | ||
226 | ret = tda18212_wr_regs(priv, 0x12, buf, sizeof(buf)); | ||
227 | if (ret) | ||
228 | goto error; | ||
229 | |||
230 | /* actual IF rounded as it is on register */ | ||
231 | priv->if_frequency = buf[3] * 50 * 1000; | ||
232 | |||
233 | exit: | ||
234 | if (fe->ops.i2c_gate_ctrl) | ||
235 | fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ | ||
236 | |||
237 | return ret; | ||
238 | |||
239 | error: | ||
240 | dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret); | ||
241 | goto exit; | ||
242 | } | ||
243 | |||
244 | static int tda18212_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
245 | { | ||
246 | struct tda18212_priv *priv = fe->tuner_priv; | ||
247 | |||
248 | *frequency = priv->if_frequency; | ||
249 | |||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | static int tda18212_release(struct dvb_frontend *fe) | ||
254 | { | ||
255 | kfree(fe->tuner_priv); | ||
256 | fe->tuner_priv = NULL; | ||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | static const struct dvb_tuner_ops tda18212_tuner_ops = { | ||
261 | .info = { | ||
262 | .name = "NXP TDA18212", | ||
263 | |||
264 | .frequency_min = 48000000, | ||
265 | .frequency_max = 864000000, | ||
266 | .frequency_step = 1000, | ||
267 | }, | ||
268 | |||
269 | .release = tda18212_release, | ||
270 | |||
271 | .set_params = tda18212_set_params, | ||
272 | .get_if_frequency = tda18212_get_if_frequency, | ||
273 | }; | ||
274 | |||
275 | struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe, | ||
276 | struct i2c_adapter *i2c, struct tda18212_config *cfg) | ||
277 | { | ||
278 | struct tda18212_priv *priv = NULL; | ||
279 | int ret; | ||
280 | u8 uninitialized_var(val); | ||
281 | |||
282 | priv = kzalloc(sizeof(struct tda18212_priv), GFP_KERNEL); | ||
283 | if (priv == NULL) | ||
284 | return NULL; | ||
285 | |||
286 | priv->cfg = cfg; | ||
287 | priv->i2c = i2c; | ||
288 | fe->tuner_priv = priv; | ||
289 | |||
290 | if (fe->ops.i2c_gate_ctrl) | ||
291 | fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ | ||
292 | |||
293 | /* check if the tuner is there */ | ||
294 | ret = tda18212_rd_reg(priv, 0x00, &val); | ||
295 | |||
296 | if (fe->ops.i2c_gate_ctrl) | ||
297 | fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ | ||
298 | |||
299 | dev_dbg(&priv->i2c->dev, "%s: ret=%d chip id=%02x\n", __func__, ret, | ||
300 | val); | ||
301 | if (ret || val != 0xc7) { | ||
302 | kfree(priv); | ||
303 | return NULL; | ||
304 | } | ||
305 | |||
306 | dev_info(&priv->i2c->dev, | ||
307 | "%s: NXP TDA18212HN successfully identified\n", | ||
308 | KBUILD_MODNAME); | ||
309 | |||
310 | memcpy(&fe->ops.tuner_ops, &tda18212_tuner_ops, | ||
311 | sizeof(struct dvb_tuner_ops)); | ||
312 | |||
313 | return fe; | ||
314 | } | ||
315 | EXPORT_SYMBOL(tda18212_attach); | ||
316 | |||
317 | MODULE_DESCRIPTION("NXP TDA18212HN silicon tuner driver"); | ||
318 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | ||
319 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/tuners/tda18212.h b/drivers/media/tuners/tda18212.h new file mode 100644 index 000000000000..9bd5da4aabb7 --- /dev/null +++ b/drivers/media/tuners/tda18212.h | |||
@@ -0,0 +1,52 @@ | |||
1 | /* | ||
2 | * NXP TDA18212HN silicon tuner driver | ||
3 | * | ||
4 | * Copyright (C) 2011 Antti Palosaari <crope@iki.fi> | ||
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 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef TDA18212_H | ||
22 | #define TDA18212_H | ||
23 | |||
24 | #include "dvb_frontend.h" | ||
25 | |||
26 | struct tda18212_config { | ||
27 | u8 i2c_address; | ||
28 | |||
29 | u16 if_dvbt_6; | ||
30 | u16 if_dvbt_7; | ||
31 | u16 if_dvbt_8; | ||
32 | u16 if_dvbt2_5; | ||
33 | u16 if_dvbt2_6; | ||
34 | u16 if_dvbt2_7; | ||
35 | u16 if_dvbt2_8; | ||
36 | u16 if_dvbc; | ||
37 | }; | ||
38 | |||
39 | #if defined(CONFIG_MEDIA_TUNER_TDA18212) || \ | ||
40 | (defined(CONFIG_MEDIA_TUNER_TDA18212_MODULE) && defined(MODULE)) | ||
41 | extern struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe, | ||
42 | struct i2c_adapter *i2c, struct tda18212_config *cfg); | ||
43 | #else | ||
44 | static inline struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe, | ||
45 | struct i2c_adapter *i2c, struct tda18212_config *cfg) | ||
46 | { | ||
47 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
48 | return NULL; | ||
49 | } | ||
50 | #endif | ||
51 | |||
52 | #endif | ||
diff --git a/drivers/media/tuners/tda18218.c b/drivers/media/tuners/tda18218.c new file mode 100644 index 000000000000..8a6f9ca788f0 --- /dev/null +++ b/drivers/media/tuners/tda18218.c | |||
@@ -0,0 +1,342 @@ | |||
1 | /* | ||
2 | * NXP TDA18218HN silicon tuner driver | ||
3 | * | ||
4 | * Copyright (C) 2010 Antti Palosaari <crope@iki.fi> | ||
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 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #include "tda18218.h" | ||
22 | #include "tda18218_priv.h" | ||
23 | |||
24 | static int debug; | ||
25 | module_param(debug, int, 0644); | ||
26 | MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); | ||
27 | |||
28 | /* write multiple registers */ | ||
29 | static int tda18218_wr_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len) | ||
30 | { | ||
31 | int ret = 0; | ||
32 | u8 buf[1+len], quotient, remainder, i, msg_len, msg_len_max; | ||
33 | struct i2c_msg msg[1] = { | ||
34 | { | ||
35 | .addr = priv->cfg->i2c_address, | ||
36 | .flags = 0, | ||
37 | .buf = buf, | ||
38 | } | ||
39 | }; | ||
40 | |||
41 | msg_len_max = priv->cfg->i2c_wr_max - 1; | ||
42 | quotient = len / msg_len_max; | ||
43 | remainder = len % msg_len_max; | ||
44 | msg_len = msg_len_max; | ||
45 | for (i = 0; (i <= quotient && remainder); i++) { | ||
46 | if (i == quotient) /* set len of the last msg */ | ||
47 | msg_len = remainder; | ||
48 | |||
49 | msg[0].len = msg_len + 1; | ||
50 | buf[0] = reg + i * msg_len_max; | ||
51 | memcpy(&buf[1], &val[i * msg_len_max], msg_len); | ||
52 | |||
53 | ret = i2c_transfer(priv->i2c, msg, 1); | ||
54 | if (ret != 1) | ||
55 | break; | ||
56 | } | ||
57 | |||
58 | if (ret == 1) { | ||
59 | ret = 0; | ||
60 | } else { | ||
61 | warn("i2c wr failed ret:%d reg:%02x len:%d", ret, reg, len); | ||
62 | ret = -EREMOTEIO; | ||
63 | } | ||
64 | |||
65 | return ret; | ||
66 | } | ||
67 | |||
68 | /* read multiple registers */ | ||
69 | static int tda18218_rd_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len) | ||
70 | { | ||
71 | int ret; | ||
72 | u8 buf[reg+len]; /* we must start read always from reg 0x00 */ | ||
73 | struct i2c_msg msg[2] = { | ||
74 | { | ||
75 | .addr = priv->cfg->i2c_address, | ||
76 | .flags = 0, | ||
77 | .len = 1, | ||
78 | .buf = "\x00", | ||
79 | }, { | ||
80 | .addr = priv->cfg->i2c_address, | ||
81 | .flags = I2C_M_RD, | ||
82 | .len = sizeof(buf), | ||
83 | .buf = buf, | ||
84 | } | ||
85 | }; | ||
86 | |||
87 | ret = i2c_transfer(priv->i2c, msg, 2); | ||
88 | if (ret == 2) { | ||
89 | memcpy(val, &buf[reg], len); | ||
90 | ret = 0; | ||
91 | } else { | ||
92 | warn("i2c rd failed ret:%d reg:%02x len:%d", ret, reg, len); | ||
93 | ret = -EREMOTEIO; | ||
94 | } | ||
95 | |||
96 | return ret; | ||
97 | } | ||
98 | |||
99 | /* write single register */ | ||
100 | static int tda18218_wr_reg(struct tda18218_priv *priv, u8 reg, u8 val) | ||
101 | { | ||
102 | return tda18218_wr_regs(priv, reg, &val, 1); | ||
103 | } | ||
104 | |||
105 | /* read single register */ | ||
106 | |||
107 | static int tda18218_rd_reg(struct tda18218_priv *priv, u8 reg, u8 *val) | ||
108 | { | ||
109 | return tda18218_rd_regs(priv, reg, val, 1); | ||
110 | } | ||
111 | |||
112 | static int tda18218_set_params(struct dvb_frontend *fe) | ||
113 | { | ||
114 | struct tda18218_priv *priv = fe->tuner_priv; | ||
115 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
116 | u32 bw = c->bandwidth_hz; | ||
117 | int ret; | ||
118 | u8 buf[3], i, BP_Filter, LP_Fc; | ||
119 | u32 LO_Frac; | ||
120 | /* TODO: find out correct AGC algorithm */ | ||
121 | u8 agc[][2] = { | ||
122 | { R20_AGC11, 0x60 }, | ||
123 | { R23_AGC21, 0x02 }, | ||
124 | { R20_AGC11, 0xa0 }, | ||
125 | { R23_AGC21, 0x09 }, | ||
126 | { R20_AGC11, 0xe0 }, | ||
127 | { R23_AGC21, 0x0c }, | ||
128 | { R20_AGC11, 0x40 }, | ||
129 | { R23_AGC21, 0x01 }, | ||
130 | { R20_AGC11, 0x80 }, | ||
131 | { R23_AGC21, 0x08 }, | ||
132 | { R20_AGC11, 0xc0 }, | ||
133 | { R23_AGC21, 0x0b }, | ||
134 | { R24_AGC22, 0x1c }, | ||
135 | { R24_AGC22, 0x0c }, | ||
136 | }; | ||
137 | |||
138 | if (fe->ops.i2c_gate_ctrl) | ||
139 | fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ | ||
140 | |||
141 | /* low-pass filter cut-off frequency */ | ||
142 | if (bw <= 6000000) { | ||
143 | LP_Fc = 0; | ||
144 | priv->if_frequency = 3000000; | ||
145 | } else if (bw <= 7000000) { | ||
146 | LP_Fc = 1; | ||
147 | priv->if_frequency = 3500000; | ||
148 | } else { | ||
149 | LP_Fc = 2; | ||
150 | priv->if_frequency = 4000000; | ||
151 | } | ||
152 | |||
153 | LO_Frac = c->frequency + priv->if_frequency; | ||
154 | |||
155 | /* band-pass filter */ | ||
156 | if (LO_Frac < 188000000) | ||
157 | BP_Filter = 3; | ||
158 | else if (LO_Frac < 253000000) | ||
159 | BP_Filter = 4; | ||
160 | else if (LO_Frac < 343000000) | ||
161 | BP_Filter = 5; | ||
162 | else | ||
163 | BP_Filter = 6; | ||
164 | |||
165 | buf[0] = (priv->regs[R1A_IF1] & ~7) | BP_Filter; /* BP_Filter */ | ||
166 | buf[1] = (priv->regs[R1B_IF2] & ~3) | LP_Fc; /* LP_Fc */ | ||
167 | buf[2] = priv->regs[R1C_AGC2B]; | ||
168 | ret = tda18218_wr_regs(priv, R1A_IF1, buf, 3); | ||
169 | if (ret) | ||
170 | goto error; | ||
171 | |||
172 | buf[0] = (LO_Frac / 1000) >> 12; /* LO_Frac_0 */ | ||
173 | buf[1] = (LO_Frac / 1000) >> 4; /* LO_Frac_1 */ | ||
174 | buf[2] = (LO_Frac / 1000) << 4 | | ||
175 | (priv->regs[R0C_MD5] & 0x0f); /* LO_Frac_2 */ | ||
176 | ret = tda18218_wr_regs(priv, R0A_MD3, buf, 3); | ||
177 | if (ret) | ||
178 | goto error; | ||
179 | |||
180 | buf[0] = priv->regs[R0F_MD8] | (1 << 6); /* Freq_prog_Start */ | ||
181 | ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1); | ||
182 | if (ret) | ||
183 | goto error; | ||
184 | |||
185 | buf[0] = priv->regs[R0F_MD8] & ~(1 << 6); /* Freq_prog_Start */ | ||
186 | ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1); | ||
187 | if (ret) | ||
188 | goto error; | ||
189 | |||
190 | /* trigger AGC */ | ||
191 | for (i = 0; i < ARRAY_SIZE(agc); i++) { | ||
192 | ret = tda18218_wr_reg(priv, agc[i][0], agc[i][1]); | ||
193 | if (ret) | ||
194 | goto error; | ||
195 | } | ||
196 | |||
197 | error: | ||
198 | if (fe->ops.i2c_gate_ctrl) | ||
199 | fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ | ||
200 | |||
201 | if (ret) | ||
202 | dbg("%s: failed ret:%d", __func__, ret); | ||
203 | |||
204 | return ret; | ||
205 | } | ||
206 | |||
207 | static int tda18218_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
208 | { | ||
209 | struct tda18218_priv *priv = fe->tuner_priv; | ||
210 | *frequency = priv->if_frequency; | ||
211 | dbg("%s: if=%d", __func__, *frequency); | ||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | static int tda18218_sleep(struct dvb_frontend *fe) | ||
216 | { | ||
217 | struct tda18218_priv *priv = fe->tuner_priv; | ||
218 | int ret; | ||
219 | |||
220 | if (fe->ops.i2c_gate_ctrl) | ||
221 | fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ | ||
222 | |||
223 | /* standby */ | ||
224 | ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0)); | ||
225 | |||
226 | if (fe->ops.i2c_gate_ctrl) | ||
227 | fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ | ||
228 | |||
229 | if (ret) | ||
230 | dbg("%s: failed ret:%d", __func__, ret); | ||
231 | |||
232 | return ret; | ||
233 | } | ||
234 | |||
235 | static int tda18218_init(struct dvb_frontend *fe) | ||
236 | { | ||
237 | struct tda18218_priv *priv = fe->tuner_priv; | ||
238 | int ret; | ||
239 | |||
240 | /* TODO: calibrations */ | ||
241 | |||
242 | if (fe->ops.i2c_gate_ctrl) | ||
243 | fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ | ||
244 | |||
245 | ret = tda18218_wr_regs(priv, R00_ID, priv->regs, TDA18218_NUM_REGS); | ||
246 | |||
247 | if (fe->ops.i2c_gate_ctrl) | ||
248 | fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ | ||
249 | |||
250 | if (ret) | ||
251 | dbg("%s: failed ret:%d", __func__, ret); | ||
252 | |||
253 | return ret; | ||
254 | } | ||
255 | |||
256 | static int tda18218_release(struct dvb_frontend *fe) | ||
257 | { | ||
258 | kfree(fe->tuner_priv); | ||
259 | fe->tuner_priv = NULL; | ||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | static const struct dvb_tuner_ops tda18218_tuner_ops = { | ||
264 | .info = { | ||
265 | .name = "NXP TDA18218", | ||
266 | |||
267 | .frequency_min = 174000000, | ||
268 | .frequency_max = 864000000, | ||
269 | .frequency_step = 1000, | ||
270 | }, | ||
271 | |||
272 | .release = tda18218_release, | ||
273 | .init = tda18218_init, | ||
274 | .sleep = tda18218_sleep, | ||
275 | |||
276 | .set_params = tda18218_set_params, | ||
277 | |||
278 | .get_if_frequency = tda18218_get_if_frequency, | ||
279 | }; | ||
280 | |||
281 | struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe, | ||
282 | struct i2c_adapter *i2c, struct tda18218_config *cfg) | ||
283 | { | ||
284 | struct tda18218_priv *priv = NULL; | ||
285 | u8 uninitialized_var(val); | ||
286 | int ret; | ||
287 | /* chip default registers values */ | ||
288 | static u8 def_regs[] = { | ||
289 | 0xc0, 0x88, 0x00, 0x8e, 0x03, 0x00, 0x00, 0xd0, 0x00, 0x40, | ||
290 | 0x00, 0x00, 0x07, 0xff, 0x84, 0x09, 0x00, 0x13, 0x00, 0x00, | ||
291 | 0x01, 0x84, 0x09, 0xf0, 0x19, 0x0a, 0x8e, 0x69, 0x98, 0x01, | ||
292 | 0x00, 0x58, 0x10, 0x40, 0x8c, 0x00, 0x0c, 0x48, 0x85, 0xc9, | ||
293 | 0xa7, 0x00, 0x00, 0x00, 0x30, 0x81, 0x80, 0x00, 0x39, 0x00, | ||
294 | 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xf6 | ||
295 | }; | ||
296 | |||
297 | priv = kzalloc(sizeof(struct tda18218_priv), GFP_KERNEL); | ||
298 | if (priv == NULL) | ||
299 | return NULL; | ||
300 | |||
301 | priv->cfg = cfg; | ||
302 | priv->i2c = i2c; | ||
303 | fe->tuner_priv = priv; | ||
304 | |||
305 | if (fe->ops.i2c_gate_ctrl) | ||
306 | fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ | ||
307 | |||
308 | /* check if the tuner is there */ | ||
309 | ret = tda18218_rd_reg(priv, R00_ID, &val); | ||
310 | dbg("%s: ret:%d chip ID:%02x", __func__, ret, val); | ||
311 | if (ret || val != def_regs[R00_ID]) { | ||
312 | kfree(priv); | ||
313 | return NULL; | ||
314 | } | ||
315 | |||
316 | info("NXP TDA18218HN successfully identified."); | ||
317 | |||
318 | memcpy(&fe->ops.tuner_ops, &tda18218_tuner_ops, | ||
319 | sizeof(struct dvb_tuner_ops)); | ||
320 | memcpy(priv->regs, def_regs, sizeof(def_regs)); | ||
321 | |||
322 | /* loop-through enabled chip default register values */ | ||
323 | if (priv->cfg->loop_through) { | ||
324 | priv->regs[R17_PD1] = 0xb0; | ||
325 | priv->regs[R18_PD2] = 0x59; | ||
326 | } | ||
327 | |||
328 | /* standby */ | ||
329 | ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0)); | ||
330 | if (ret) | ||
331 | dbg("%s: failed ret:%d", __func__, ret); | ||
332 | |||
333 | if (fe->ops.i2c_gate_ctrl) | ||
334 | fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ | ||
335 | |||
336 | return fe; | ||
337 | } | ||
338 | EXPORT_SYMBOL(tda18218_attach); | ||
339 | |||
340 | MODULE_DESCRIPTION("NXP TDA18218HN silicon tuner driver"); | ||
341 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | ||
342 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/tuners/tda18218.h b/drivers/media/tuners/tda18218.h new file mode 100644 index 000000000000..b4180d180029 --- /dev/null +++ b/drivers/media/tuners/tda18218.h | |||
@@ -0,0 +1,45 @@ | |||
1 | /* | ||
2 | * NXP TDA18218HN silicon tuner driver | ||
3 | * | ||
4 | * Copyright (C) 2010 Antti Palosaari <crope@iki.fi> | ||
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 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef TDA18218_H | ||
22 | #define TDA18218_H | ||
23 | |||
24 | #include "dvb_frontend.h" | ||
25 | |||
26 | struct tda18218_config { | ||
27 | u8 i2c_address; | ||
28 | u8 i2c_wr_max; | ||
29 | u8 loop_through:1; | ||
30 | }; | ||
31 | |||
32 | #if defined(CONFIG_MEDIA_TUNER_TDA18218) || \ | ||
33 | (defined(CONFIG_MEDIA_TUNER_TDA18218_MODULE) && defined(MODULE)) | ||
34 | extern struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe, | ||
35 | struct i2c_adapter *i2c, struct tda18218_config *cfg); | ||
36 | #else | ||
37 | static inline struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe, | ||
38 | struct i2c_adapter *i2c, struct tda18218_config *cfg) | ||
39 | { | ||
40 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
41 | return NULL; | ||
42 | } | ||
43 | #endif | ||
44 | |||
45 | #endif | ||
diff --git a/drivers/media/tuners/tda18218_priv.h b/drivers/media/tuners/tda18218_priv.h new file mode 100644 index 000000000000..dc52b72e1407 --- /dev/null +++ b/drivers/media/tuners/tda18218_priv.h | |||
@@ -0,0 +1,108 @@ | |||
1 | /* | ||
2 | * NXP TDA18218HN silicon tuner driver | ||
3 | * | ||
4 | * Copyright (C) 2010 Antti Palosaari <crope@iki.fi> | ||
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 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef TDA18218_PRIV_H | ||
22 | #define TDA18218_PRIV_H | ||
23 | |||
24 | #define LOG_PREFIX "tda18218" | ||
25 | |||
26 | #undef dbg | ||
27 | #define dbg(f, arg...) \ | ||
28 | if (debug) \ | ||
29 | printk(KERN_DEBUG LOG_PREFIX": " f "\n" , ## arg) | ||
30 | #undef err | ||
31 | #define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) | ||
32 | #undef info | ||
33 | #define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) | ||
34 | #undef warn | ||
35 | #define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) | ||
36 | |||
37 | #define R00_ID 0x00 /* ID byte */ | ||
38 | #define R01_R1 0x01 /* Read byte 1 */ | ||
39 | #define R02_R2 0x02 /* Read byte 2 */ | ||
40 | #define R03_R3 0x03 /* Read byte 3 */ | ||
41 | #define R04_R4 0x04 /* Read byte 4 */ | ||
42 | #define R05_R5 0x05 /* Read byte 5 */ | ||
43 | #define R06_R6 0x06 /* Read byte 6 */ | ||
44 | #define R07_MD1 0x07 /* Main divider byte 1 */ | ||
45 | #define R08_PSM1 0x08 /* PSM byte 1 */ | ||
46 | #define R09_MD2 0x09 /* Main divider byte 2 */ | ||
47 | #define R0A_MD3 0x0a /* Main divider byte 1 */ | ||
48 | #define R0B_MD4 0x0b /* Main divider byte 4 */ | ||
49 | #define R0C_MD5 0x0c /* Main divider byte 5 */ | ||
50 | #define R0D_MD6 0x0d /* Main divider byte 6 */ | ||
51 | #define R0E_MD7 0x0e /* Main divider byte 7 */ | ||
52 | #define R0F_MD8 0x0f /* Main divider byte 8 */ | ||
53 | #define R10_CD1 0x10 /* Call divider byte 1 */ | ||
54 | #define R11_CD2 0x11 /* Call divider byte 2 */ | ||
55 | #define R12_CD3 0x12 /* Call divider byte 3 */ | ||
56 | #define R13_CD4 0x13 /* Call divider byte 4 */ | ||
57 | #define R14_CD5 0x14 /* Call divider byte 5 */ | ||
58 | #define R15_CD6 0x15 /* Call divider byte 6 */ | ||
59 | #define R16_CD7 0x16 /* Call divider byte 7 */ | ||
60 | #define R17_PD1 0x17 /* Power-down byte 1 */ | ||
61 | #define R18_PD2 0x18 /* Power-down byte 2 */ | ||
62 | #define R19_XTOUT 0x19 /* XTOUT byte */ | ||
63 | #define R1A_IF1 0x1a /* IF byte 1 */ | ||
64 | #define R1B_IF2 0x1b /* IF byte 2 */ | ||
65 | #define R1C_AGC2B 0x1c /* AGC2b byte */ | ||
66 | #define R1D_PSM2 0x1d /* PSM byte 2 */ | ||
67 | #define R1E_PSM3 0x1e /* PSM byte 3 */ | ||
68 | #define R1F_PSM4 0x1f /* PSM byte 4 */ | ||
69 | #define R20_AGC11 0x20 /* AGC1 byte 1 */ | ||
70 | #define R21_AGC12 0x21 /* AGC1 byte 2 */ | ||
71 | #define R22_AGC13 0x22 /* AGC1 byte 3 */ | ||
72 | #define R23_AGC21 0x23 /* AGC2 byte 1 */ | ||
73 | #define R24_AGC22 0x24 /* AGC2 byte 2 */ | ||
74 | #define R25_AAGC 0x25 /* Analog AGC byte */ | ||
75 | #define R26_RC 0x26 /* RC byte */ | ||
76 | #define R27_RSSI 0x27 /* RSSI byte */ | ||
77 | #define R28_IRCAL1 0x28 /* IR CAL byte 1 */ | ||
78 | #define R29_IRCAL2 0x29 /* IR CAL byte 2 */ | ||
79 | #define R2A_IRCAL3 0x2a /* IR CAL byte 3 */ | ||
80 | #define R2B_IRCAL4 0x2b /* IR CAL byte 4 */ | ||
81 | #define R2C_RFCAL1 0x2c /* RF CAL byte 1 */ | ||
82 | #define R2D_RFCAL2 0x2d /* RF CAL byte 2 */ | ||
83 | #define R2E_RFCAL3 0x2e /* RF CAL byte 3 */ | ||
84 | #define R2F_RFCAL4 0x2f /* RF CAL byte 4 */ | ||
85 | #define R30_RFCAL5 0x30 /* RF CAL byte 5 */ | ||
86 | #define R31_RFCAL6 0x31 /* RF CAL byte 6 */ | ||
87 | #define R32_RFCAL7 0x32 /* RF CAL byte 7 */ | ||
88 | #define R33_RFCAL8 0x33 /* RF CAL byte 8 */ | ||
89 | #define R34_RFCAL9 0x34 /* RF CAL byte 9 */ | ||
90 | #define R35_RFCAL10 0x35 /* RF CAL byte 10 */ | ||
91 | #define R36_RFCALRAM1 0x36 /* RF CAL RAM byte 1 */ | ||
92 | #define R37_RFCALRAM2 0x37 /* RF CAL RAM byte 2 */ | ||
93 | #define R38_MARGIN 0x38 /* Margin byte */ | ||
94 | #define R39_FMAX1 0x39 /* Fmax byte 1 */ | ||
95 | #define R3A_FMAX2 0x3a /* Fmax byte 2 */ | ||
96 | |||
97 | #define TDA18218_NUM_REGS 59 | ||
98 | |||
99 | struct tda18218_priv { | ||
100 | struct tda18218_config *cfg; | ||
101 | struct i2c_adapter *i2c; | ||
102 | |||
103 | u32 if_frequency; | ||
104 | |||
105 | u8 regs[TDA18218_NUM_REGS]; | ||
106 | }; | ||
107 | |||
108 | #endif | ||
diff --git a/drivers/media/tuners/tda18271-common.c b/drivers/media/tuners/tda18271-common.c new file mode 100644 index 000000000000..39c645787b62 --- /dev/null +++ b/drivers/media/tuners/tda18271-common.c | |||
@@ -0,0 +1,703 @@ | |||
1 | /* | ||
2 | tda18271-common.c - driver for the Philips / NXP TDA18271 silicon tuner | ||
3 | |||
4 | Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org> | ||
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 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #include "tda18271-priv.h" | ||
22 | |||
23 | static int tda18271_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) | ||
24 | { | ||
25 | struct tda18271_priv *priv = fe->tuner_priv; | ||
26 | enum tda18271_i2c_gate gate; | ||
27 | int ret = 0; | ||
28 | |||
29 | switch (priv->gate) { | ||
30 | case TDA18271_GATE_DIGITAL: | ||
31 | case TDA18271_GATE_ANALOG: | ||
32 | gate = priv->gate; | ||
33 | break; | ||
34 | case TDA18271_GATE_AUTO: | ||
35 | default: | ||
36 | switch (priv->mode) { | ||
37 | case TDA18271_DIGITAL: | ||
38 | gate = TDA18271_GATE_DIGITAL; | ||
39 | break; | ||
40 | case TDA18271_ANALOG: | ||
41 | default: | ||
42 | gate = TDA18271_GATE_ANALOG; | ||
43 | break; | ||
44 | } | ||
45 | } | ||
46 | |||
47 | switch (gate) { | ||
48 | case TDA18271_GATE_ANALOG: | ||
49 | if (fe->ops.analog_ops.i2c_gate_ctrl) | ||
50 | ret = fe->ops.analog_ops.i2c_gate_ctrl(fe, enable); | ||
51 | break; | ||
52 | case TDA18271_GATE_DIGITAL: | ||
53 | if (fe->ops.i2c_gate_ctrl) | ||
54 | ret = fe->ops.i2c_gate_ctrl(fe, enable); | ||
55 | break; | ||
56 | default: | ||
57 | ret = -EINVAL; | ||
58 | break; | ||
59 | } | ||
60 | |||
61 | return ret; | ||
62 | }; | ||
63 | |||
64 | /*---------------------------------------------------------------------*/ | ||
65 | |||
66 | static void tda18271_dump_regs(struct dvb_frontend *fe, int extended) | ||
67 | { | ||
68 | struct tda18271_priv *priv = fe->tuner_priv; | ||
69 | unsigned char *regs = priv->tda18271_regs; | ||
70 | |||
71 | tda_reg("=== TDA18271 REG DUMP ===\n"); | ||
72 | tda_reg("ID_BYTE = 0x%02x\n", 0xff & regs[R_ID]); | ||
73 | tda_reg("THERMO_BYTE = 0x%02x\n", 0xff & regs[R_TM]); | ||
74 | tda_reg("POWER_LEVEL_BYTE = 0x%02x\n", 0xff & regs[R_PL]); | ||
75 | tda_reg("EASY_PROG_BYTE_1 = 0x%02x\n", 0xff & regs[R_EP1]); | ||
76 | tda_reg("EASY_PROG_BYTE_2 = 0x%02x\n", 0xff & regs[R_EP2]); | ||
77 | tda_reg("EASY_PROG_BYTE_3 = 0x%02x\n", 0xff & regs[R_EP3]); | ||
78 | tda_reg("EASY_PROG_BYTE_4 = 0x%02x\n", 0xff & regs[R_EP4]); | ||
79 | tda_reg("EASY_PROG_BYTE_5 = 0x%02x\n", 0xff & regs[R_EP5]); | ||
80 | tda_reg("CAL_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_CPD]); | ||
81 | tda_reg("CAL_DIV_BYTE_1 = 0x%02x\n", 0xff & regs[R_CD1]); | ||
82 | tda_reg("CAL_DIV_BYTE_2 = 0x%02x\n", 0xff & regs[R_CD2]); | ||
83 | tda_reg("CAL_DIV_BYTE_3 = 0x%02x\n", 0xff & regs[R_CD3]); | ||
84 | tda_reg("MAIN_POST_DIV_BYTE = 0x%02x\n", 0xff & regs[R_MPD]); | ||
85 | tda_reg("MAIN_DIV_BYTE_1 = 0x%02x\n", 0xff & regs[R_MD1]); | ||
86 | tda_reg("MAIN_DIV_BYTE_2 = 0x%02x\n", 0xff & regs[R_MD2]); | ||
87 | tda_reg("MAIN_DIV_BYTE_3 = 0x%02x\n", 0xff & regs[R_MD3]); | ||
88 | |||
89 | /* only dump extended regs if DBG_ADV is set */ | ||
90 | if (!(tda18271_debug & DBG_ADV)) | ||
91 | return; | ||
92 | |||
93 | /* W indicates write-only registers. | ||
94 | * Register dump for write-only registers shows last value written. */ | ||
95 | |||
96 | tda_reg("EXTENDED_BYTE_1 = 0x%02x\n", 0xff & regs[R_EB1]); | ||
97 | tda_reg("EXTENDED_BYTE_2 = 0x%02x\n", 0xff & regs[R_EB2]); | ||
98 | tda_reg("EXTENDED_BYTE_3 = 0x%02x\n", 0xff & regs[R_EB3]); | ||
99 | tda_reg("EXTENDED_BYTE_4 = 0x%02x\n", 0xff & regs[R_EB4]); | ||
100 | tda_reg("EXTENDED_BYTE_5 = 0x%02x\n", 0xff & regs[R_EB5]); | ||
101 | tda_reg("EXTENDED_BYTE_6 = 0x%02x\n", 0xff & regs[R_EB6]); | ||
102 | tda_reg("EXTENDED_BYTE_7 = 0x%02x\n", 0xff & regs[R_EB7]); | ||
103 | tda_reg("EXTENDED_BYTE_8 = 0x%02x\n", 0xff & regs[R_EB8]); | ||
104 | tda_reg("EXTENDED_BYTE_9 W = 0x%02x\n", 0xff & regs[R_EB9]); | ||
105 | tda_reg("EXTENDED_BYTE_10 = 0x%02x\n", 0xff & regs[R_EB10]); | ||
106 | tda_reg("EXTENDED_BYTE_11 = 0x%02x\n", 0xff & regs[R_EB11]); | ||
107 | tda_reg("EXTENDED_BYTE_12 = 0x%02x\n", 0xff & regs[R_EB12]); | ||
108 | tda_reg("EXTENDED_BYTE_13 = 0x%02x\n", 0xff & regs[R_EB13]); | ||
109 | tda_reg("EXTENDED_BYTE_14 = 0x%02x\n", 0xff & regs[R_EB14]); | ||
110 | tda_reg("EXTENDED_BYTE_15 = 0x%02x\n", 0xff & regs[R_EB15]); | ||
111 | tda_reg("EXTENDED_BYTE_16 W = 0x%02x\n", 0xff & regs[R_EB16]); | ||
112 | tda_reg("EXTENDED_BYTE_17 W = 0x%02x\n", 0xff & regs[R_EB17]); | ||
113 | tda_reg("EXTENDED_BYTE_18 = 0x%02x\n", 0xff & regs[R_EB18]); | ||
114 | tda_reg("EXTENDED_BYTE_19 W = 0x%02x\n", 0xff & regs[R_EB19]); | ||
115 | tda_reg("EXTENDED_BYTE_20 W = 0x%02x\n", 0xff & regs[R_EB20]); | ||
116 | tda_reg("EXTENDED_BYTE_21 = 0x%02x\n", 0xff & regs[R_EB21]); | ||
117 | tda_reg("EXTENDED_BYTE_22 = 0x%02x\n", 0xff & regs[R_EB22]); | ||
118 | tda_reg("EXTENDED_BYTE_23 = 0x%02x\n", 0xff & regs[R_EB23]); | ||
119 | } | ||
120 | |||
121 | int tda18271_read_regs(struct dvb_frontend *fe) | ||
122 | { | ||
123 | struct tda18271_priv *priv = fe->tuner_priv; | ||
124 | unsigned char *regs = priv->tda18271_regs; | ||
125 | unsigned char buf = 0x00; | ||
126 | int ret; | ||
127 | struct i2c_msg msg[] = { | ||
128 | { .addr = priv->i2c_props.addr, .flags = 0, | ||
129 | .buf = &buf, .len = 1 }, | ||
130 | { .addr = priv->i2c_props.addr, .flags = I2C_M_RD, | ||
131 | .buf = regs, .len = 16 } | ||
132 | }; | ||
133 | |||
134 | tda18271_i2c_gate_ctrl(fe, 1); | ||
135 | |||
136 | /* read all registers */ | ||
137 | ret = i2c_transfer(priv->i2c_props.adap, msg, 2); | ||
138 | |||
139 | tda18271_i2c_gate_ctrl(fe, 0); | ||
140 | |||
141 | if (ret != 2) | ||
142 | tda_err("ERROR: i2c_transfer returned: %d\n", ret); | ||
143 | |||
144 | if (tda18271_debug & DBG_REG) | ||
145 | tda18271_dump_regs(fe, 0); | ||
146 | |||
147 | return (ret == 2 ? 0 : ret); | ||
148 | } | ||
149 | |||
150 | int tda18271_read_extended(struct dvb_frontend *fe) | ||
151 | { | ||
152 | struct tda18271_priv *priv = fe->tuner_priv; | ||
153 | unsigned char *regs = priv->tda18271_regs; | ||
154 | unsigned char regdump[TDA18271_NUM_REGS]; | ||
155 | unsigned char buf = 0x00; | ||
156 | int ret, i; | ||
157 | struct i2c_msg msg[] = { | ||
158 | { .addr = priv->i2c_props.addr, .flags = 0, | ||
159 | .buf = &buf, .len = 1 }, | ||
160 | { .addr = priv->i2c_props.addr, .flags = I2C_M_RD, | ||
161 | .buf = regdump, .len = TDA18271_NUM_REGS } | ||
162 | }; | ||
163 | |||
164 | tda18271_i2c_gate_ctrl(fe, 1); | ||
165 | |||
166 | /* read all registers */ | ||
167 | ret = i2c_transfer(priv->i2c_props.adap, msg, 2); | ||
168 | |||
169 | tda18271_i2c_gate_ctrl(fe, 0); | ||
170 | |||
171 | if (ret != 2) | ||
172 | tda_err("ERROR: i2c_transfer returned: %d\n", ret); | ||
173 | |||
174 | for (i = 0; i < TDA18271_NUM_REGS; i++) { | ||
175 | /* don't update write-only registers */ | ||
176 | if ((i != R_EB9) && | ||
177 | (i != R_EB16) && | ||
178 | (i != R_EB17) && | ||
179 | (i != R_EB19) && | ||
180 | (i != R_EB20)) | ||
181 | regs[i] = regdump[i]; | ||
182 | } | ||
183 | |||
184 | if (tda18271_debug & DBG_REG) | ||
185 | tda18271_dump_regs(fe, 1); | ||
186 | |||
187 | return (ret == 2 ? 0 : ret); | ||
188 | } | ||
189 | |||
190 | int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len) | ||
191 | { | ||
192 | struct tda18271_priv *priv = fe->tuner_priv; | ||
193 | unsigned char *regs = priv->tda18271_regs; | ||
194 | unsigned char buf[TDA18271_NUM_REGS + 1]; | ||
195 | struct i2c_msg msg = { .addr = priv->i2c_props.addr, .flags = 0, | ||
196 | .buf = buf }; | ||
197 | int i, ret = 1, max; | ||
198 | |||
199 | BUG_ON((len == 0) || (idx + len > sizeof(buf))); | ||
200 | |||
201 | |||
202 | switch (priv->small_i2c) { | ||
203 | case TDA18271_03_BYTE_CHUNK_INIT: | ||
204 | max = 3; | ||
205 | break; | ||
206 | case TDA18271_08_BYTE_CHUNK_INIT: | ||
207 | max = 8; | ||
208 | break; | ||
209 | case TDA18271_16_BYTE_CHUNK_INIT: | ||
210 | max = 16; | ||
211 | break; | ||
212 | case TDA18271_39_BYTE_CHUNK_INIT: | ||
213 | default: | ||
214 | max = 39; | ||
215 | } | ||
216 | |||
217 | tda18271_i2c_gate_ctrl(fe, 1); | ||
218 | while (len) { | ||
219 | if (max > len) | ||
220 | max = len; | ||
221 | |||
222 | buf[0] = idx; | ||
223 | for (i = 1; i <= max; i++) | ||
224 | buf[i] = regs[idx - 1 + i]; | ||
225 | |||
226 | msg.len = max + 1; | ||
227 | |||
228 | /* write registers */ | ||
229 | ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); | ||
230 | if (ret != 1) | ||
231 | break; | ||
232 | |||
233 | idx += max; | ||
234 | len -= max; | ||
235 | } | ||
236 | tda18271_i2c_gate_ctrl(fe, 0); | ||
237 | |||
238 | if (ret != 1) | ||
239 | tda_err("ERROR: idx = 0x%x, len = %d, " | ||
240 | "i2c_transfer returned: %d\n", idx, max, ret); | ||
241 | |||
242 | return (ret == 1 ? 0 : ret); | ||
243 | } | ||
244 | |||
245 | /*---------------------------------------------------------------------*/ | ||
246 | |||
247 | int tda18271_charge_pump_source(struct dvb_frontend *fe, | ||
248 | enum tda18271_pll pll, int force) | ||
249 | { | ||
250 | struct tda18271_priv *priv = fe->tuner_priv; | ||
251 | unsigned char *regs = priv->tda18271_regs; | ||
252 | |||
253 | int r_cp = (pll == TDA18271_CAL_PLL) ? R_EB7 : R_EB4; | ||
254 | |||
255 | regs[r_cp] &= ~0x20; | ||
256 | regs[r_cp] |= ((force & 1) << 5); | ||
257 | |||
258 | return tda18271_write_regs(fe, r_cp, 1); | ||
259 | } | ||
260 | |||
261 | int tda18271_init_regs(struct dvb_frontend *fe) | ||
262 | { | ||
263 | struct tda18271_priv *priv = fe->tuner_priv; | ||
264 | unsigned char *regs = priv->tda18271_regs; | ||
265 | |||
266 | tda_dbg("initializing registers for device @ %d-%04x\n", | ||
267 | i2c_adapter_id(priv->i2c_props.adap), | ||
268 | priv->i2c_props.addr); | ||
269 | |||
270 | /* initialize registers */ | ||
271 | switch (priv->id) { | ||
272 | case TDA18271HDC1: | ||
273 | regs[R_ID] = 0x83; | ||
274 | break; | ||
275 | case TDA18271HDC2: | ||
276 | regs[R_ID] = 0x84; | ||
277 | break; | ||
278 | }; | ||
279 | |||
280 | regs[R_TM] = 0x08; | ||
281 | regs[R_PL] = 0x80; | ||
282 | regs[R_EP1] = 0xc6; | ||
283 | regs[R_EP2] = 0xdf; | ||
284 | regs[R_EP3] = 0x16; | ||
285 | regs[R_EP4] = 0x60; | ||
286 | regs[R_EP5] = 0x80; | ||
287 | regs[R_CPD] = 0x80; | ||
288 | regs[R_CD1] = 0x00; | ||
289 | regs[R_CD2] = 0x00; | ||
290 | regs[R_CD3] = 0x00; | ||
291 | regs[R_MPD] = 0x00; | ||
292 | regs[R_MD1] = 0x00; | ||
293 | regs[R_MD2] = 0x00; | ||
294 | regs[R_MD3] = 0x00; | ||
295 | |||
296 | switch (priv->id) { | ||
297 | case TDA18271HDC1: | ||
298 | regs[R_EB1] = 0xff; | ||
299 | break; | ||
300 | case TDA18271HDC2: | ||
301 | regs[R_EB1] = 0xfc; | ||
302 | break; | ||
303 | }; | ||
304 | |||
305 | regs[R_EB2] = 0x01; | ||
306 | regs[R_EB3] = 0x84; | ||
307 | regs[R_EB4] = 0x41; | ||
308 | regs[R_EB5] = 0x01; | ||
309 | regs[R_EB6] = 0x84; | ||
310 | regs[R_EB7] = 0x40; | ||
311 | regs[R_EB8] = 0x07; | ||
312 | regs[R_EB9] = 0x00; | ||
313 | regs[R_EB10] = 0x00; | ||
314 | regs[R_EB11] = 0x96; | ||
315 | |||
316 | switch (priv->id) { | ||
317 | case TDA18271HDC1: | ||
318 | regs[R_EB12] = 0x0f; | ||
319 | break; | ||
320 | case TDA18271HDC2: | ||
321 | regs[R_EB12] = 0x33; | ||
322 | break; | ||
323 | }; | ||
324 | |||
325 | regs[R_EB13] = 0xc1; | ||
326 | regs[R_EB14] = 0x00; | ||
327 | regs[R_EB15] = 0x8f; | ||
328 | regs[R_EB16] = 0x00; | ||
329 | regs[R_EB17] = 0x00; | ||
330 | |||
331 | switch (priv->id) { | ||
332 | case TDA18271HDC1: | ||
333 | regs[R_EB18] = 0x00; | ||
334 | break; | ||
335 | case TDA18271HDC2: | ||
336 | regs[R_EB18] = 0x8c; | ||
337 | break; | ||
338 | }; | ||
339 | |||
340 | regs[R_EB19] = 0x00; | ||
341 | regs[R_EB20] = 0x20; | ||
342 | |||
343 | switch (priv->id) { | ||
344 | case TDA18271HDC1: | ||
345 | regs[R_EB21] = 0x33; | ||
346 | break; | ||
347 | case TDA18271HDC2: | ||
348 | regs[R_EB21] = 0xb3; | ||
349 | break; | ||
350 | }; | ||
351 | |||
352 | regs[R_EB22] = 0x48; | ||
353 | regs[R_EB23] = 0xb0; | ||
354 | |||
355 | tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS); | ||
356 | |||
357 | /* setup agc1 gain */ | ||
358 | regs[R_EB17] = 0x00; | ||
359 | tda18271_write_regs(fe, R_EB17, 1); | ||
360 | regs[R_EB17] = 0x03; | ||
361 | tda18271_write_regs(fe, R_EB17, 1); | ||
362 | regs[R_EB17] = 0x43; | ||
363 | tda18271_write_regs(fe, R_EB17, 1); | ||
364 | regs[R_EB17] = 0x4c; | ||
365 | tda18271_write_regs(fe, R_EB17, 1); | ||
366 | |||
367 | /* setup agc2 gain */ | ||
368 | if ((priv->id) == TDA18271HDC1) { | ||
369 | regs[R_EB20] = 0xa0; | ||
370 | tda18271_write_regs(fe, R_EB20, 1); | ||
371 | regs[R_EB20] = 0xa7; | ||
372 | tda18271_write_regs(fe, R_EB20, 1); | ||
373 | regs[R_EB20] = 0xe7; | ||
374 | tda18271_write_regs(fe, R_EB20, 1); | ||
375 | regs[R_EB20] = 0xec; | ||
376 | tda18271_write_regs(fe, R_EB20, 1); | ||
377 | } | ||
378 | |||
379 | /* image rejection calibration */ | ||
380 | |||
381 | /* low-band */ | ||
382 | regs[R_EP3] = 0x1f; | ||
383 | regs[R_EP4] = 0x66; | ||
384 | regs[R_EP5] = 0x81; | ||
385 | regs[R_CPD] = 0xcc; | ||
386 | regs[R_CD1] = 0x6c; | ||
387 | regs[R_CD2] = 0x00; | ||
388 | regs[R_CD3] = 0x00; | ||
389 | regs[R_MPD] = 0xcd; | ||
390 | regs[R_MD1] = 0x77; | ||
391 | regs[R_MD2] = 0x08; | ||
392 | regs[R_MD3] = 0x00; | ||
393 | |||
394 | tda18271_write_regs(fe, R_EP3, 11); | ||
395 | |||
396 | if ((priv->id) == TDA18271HDC2) { | ||
397 | /* main pll cp source on */ | ||
398 | tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 1); | ||
399 | msleep(1); | ||
400 | |||
401 | /* main pll cp source off */ | ||
402 | tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 0); | ||
403 | } | ||
404 | |||
405 | msleep(5); /* pll locking */ | ||
406 | |||
407 | /* launch detector */ | ||
408 | tda18271_write_regs(fe, R_EP1, 1); | ||
409 | msleep(5); /* wanted low measurement */ | ||
410 | |||
411 | regs[R_EP5] = 0x85; | ||
412 | regs[R_CPD] = 0xcb; | ||
413 | regs[R_CD1] = 0x66; | ||
414 | regs[R_CD2] = 0x70; | ||
415 | |||
416 | tda18271_write_regs(fe, R_EP3, 7); | ||
417 | msleep(5); /* pll locking */ | ||
418 | |||
419 | /* launch optimization algorithm */ | ||
420 | tda18271_write_regs(fe, R_EP2, 1); | ||
421 | msleep(30); /* image low optimization completion */ | ||
422 | |||
423 | /* mid-band */ | ||
424 | regs[R_EP5] = 0x82; | ||
425 | regs[R_CPD] = 0xa8; | ||
426 | regs[R_CD2] = 0x00; | ||
427 | regs[R_MPD] = 0xa9; | ||
428 | regs[R_MD1] = 0x73; | ||
429 | regs[R_MD2] = 0x1a; | ||
430 | |||
431 | tda18271_write_regs(fe, R_EP3, 11); | ||
432 | msleep(5); /* pll locking */ | ||
433 | |||
434 | /* launch detector */ | ||
435 | tda18271_write_regs(fe, R_EP1, 1); | ||
436 | msleep(5); /* wanted mid measurement */ | ||
437 | |||
438 | regs[R_EP5] = 0x86; | ||
439 | regs[R_CPD] = 0xa8; | ||
440 | regs[R_CD1] = 0x66; | ||
441 | regs[R_CD2] = 0xa0; | ||
442 | |||
443 | tda18271_write_regs(fe, R_EP3, 7); | ||
444 | msleep(5); /* pll locking */ | ||
445 | |||
446 | /* launch optimization algorithm */ | ||
447 | tda18271_write_regs(fe, R_EP2, 1); | ||
448 | msleep(30); /* image mid optimization completion */ | ||
449 | |||
450 | /* high-band */ | ||
451 | regs[R_EP5] = 0x83; | ||
452 | regs[R_CPD] = 0x98; | ||
453 | regs[R_CD1] = 0x65; | ||
454 | regs[R_CD2] = 0x00; | ||
455 | regs[R_MPD] = 0x99; | ||
456 | regs[R_MD1] = 0x71; | ||
457 | regs[R_MD2] = 0xcd; | ||
458 | |||
459 | tda18271_write_regs(fe, R_EP3, 11); | ||
460 | msleep(5); /* pll locking */ | ||
461 | |||
462 | /* launch detector */ | ||
463 | tda18271_write_regs(fe, R_EP1, 1); | ||
464 | msleep(5); /* wanted high measurement */ | ||
465 | |||
466 | regs[R_EP5] = 0x87; | ||
467 | regs[R_CD1] = 0x65; | ||
468 | regs[R_CD2] = 0x50; | ||
469 | |||
470 | tda18271_write_regs(fe, R_EP3, 7); | ||
471 | msleep(5); /* pll locking */ | ||
472 | |||
473 | /* launch optimization algorithm */ | ||
474 | tda18271_write_regs(fe, R_EP2, 1); | ||
475 | msleep(30); /* image high optimization completion */ | ||
476 | |||
477 | /* return to normal mode */ | ||
478 | regs[R_EP4] = 0x64; | ||
479 | tda18271_write_regs(fe, R_EP4, 1); | ||
480 | |||
481 | /* synchronize */ | ||
482 | tda18271_write_regs(fe, R_EP1, 1); | ||
483 | |||
484 | return 0; | ||
485 | } | ||
486 | |||
487 | /*---------------------------------------------------------------------*/ | ||
488 | |||
489 | /* | ||
490 | * Standby modes, EP3 [7:5] | ||
491 | * | ||
492 | * | SM || SM_LT || SM_XT || mode description | ||
493 | * |=====\\=======\\=======\\=================================== | ||
494 | * | 0 || 0 || 0 || normal mode | ||
495 | * |-----||-------||-------||----------------------------------- | ||
496 | * | || || || standby mode w/ slave tuner output | ||
497 | * | 1 || 0 || 0 || & loop thru & xtal oscillator on | ||
498 | * |-----||-------||-------||----------------------------------- | ||
499 | * | 1 || 1 || 0 || standby mode w/ xtal oscillator on | ||
500 | * |-----||-------||-------||----------------------------------- | ||
501 | * | 1 || 1 || 1 || power off | ||
502 | * | ||
503 | */ | ||
504 | |||
505 | int tda18271_set_standby_mode(struct dvb_frontend *fe, | ||
506 | int sm, int sm_lt, int sm_xt) | ||
507 | { | ||
508 | struct tda18271_priv *priv = fe->tuner_priv; | ||
509 | unsigned char *regs = priv->tda18271_regs; | ||
510 | |||
511 | if (tda18271_debug & DBG_ADV) | ||
512 | tda_dbg("sm = %d, sm_lt = %d, sm_xt = %d\n", sm, sm_lt, sm_xt); | ||
513 | |||
514 | regs[R_EP3] &= ~0xe0; /* clear sm, sm_lt, sm_xt */ | ||
515 | regs[R_EP3] |= (sm ? (1 << 7) : 0) | | ||
516 | (sm_lt ? (1 << 6) : 0) | | ||
517 | (sm_xt ? (1 << 5) : 0); | ||
518 | |||
519 | return tda18271_write_regs(fe, R_EP3, 1); | ||
520 | } | ||
521 | |||
522 | /*---------------------------------------------------------------------*/ | ||
523 | |||
524 | int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq) | ||
525 | { | ||
526 | /* sets main post divider & divider bytes, but does not write them */ | ||
527 | struct tda18271_priv *priv = fe->tuner_priv; | ||
528 | unsigned char *regs = priv->tda18271_regs; | ||
529 | u8 d, pd; | ||
530 | u32 div; | ||
531 | |||
532 | int ret = tda18271_lookup_pll_map(fe, MAIN_PLL, &freq, &pd, &d); | ||
533 | if (tda_fail(ret)) | ||
534 | goto fail; | ||
535 | |||
536 | regs[R_MPD] = (0x7f & pd); | ||
537 | |||
538 | div = ((d * (freq / 1000)) << 7) / 125; | ||
539 | |||
540 | regs[R_MD1] = 0x7f & (div >> 16); | ||
541 | regs[R_MD2] = 0xff & (div >> 8); | ||
542 | regs[R_MD3] = 0xff & div; | ||
543 | fail: | ||
544 | return ret; | ||
545 | } | ||
546 | |||
547 | int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq) | ||
548 | { | ||
549 | /* sets cal post divider & divider bytes, but does not write them */ | ||
550 | struct tda18271_priv *priv = fe->tuner_priv; | ||
551 | unsigned char *regs = priv->tda18271_regs; | ||
552 | u8 d, pd; | ||
553 | u32 div; | ||
554 | |||
555 | int ret = tda18271_lookup_pll_map(fe, CAL_PLL, &freq, &pd, &d); | ||
556 | if (tda_fail(ret)) | ||
557 | goto fail; | ||
558 | |||
559 | regs[R_CPD] = pd; | ||
560 | |||
561 | div = ((d * (freq / 1000)) << 7) / 125; | ||
562 | |||
563 | regs[R_CD1] = 0x7f & (div >> 16); | ||
564 | regs[R_CD2] = 0xff & (div >> 8); | ||
565 | regs[R_CD3] = 0xff & div; | ||
566 | fail: | ||
567 | return ret; | ||
568 | } | ||
569 | |||
570 | /*---------------------------------------------------------------------*/ | ||
571 | |||
572 | int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq) | ||
573 | { | ||
574 | /* sets bp filter bits, but does not write them */ | ||
575 | struct tda18271_priv *priv = fe->tuner_priv; | ||
576 | unsigned char *regs = priv->tda18271_regs; | ||
577 | u8 val; | ||
578 | |||
579 | int ret = tda18271_lookup_map(fe, BP_FILTER, freq, &val); | ||
580 | if (tda_fail(ret)) | ||
581 | goto fail; | ||
582 | |||
583 | regs[R_EP1] &= ~0x07; /* clear bp filter bits */ | ||
584 | regs[R_EP1] |= (0x07 & val); | ||
585 | fail: | ||
586 | return ret; | ||
587 | } | ||
588 | |||
589 | int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq) | ||
590 | { | ||
591 | /* sets K & M bits, but does not write them */ | ||
592 | struct tda18271_priv *priv = fe->tuner_priv; | ||
593 | unsigned char *regs = priv->tda18271_regs; | ||
594 | u8 val; | ||
595 | |||
596 | int ret = tda18271_lookup_map(fe, RF_CAL_KMCO, freq, &val); | ||
597 | if (tda_fail(ret)) | ||
598 | goto fail; | ||
599 | |||
600 | regs[R_EB13] &= ~0x7c; /* clear k & m bits */ | ||
601 | regs[R_EB13] |= (0x7c & val); | ||
602 | fail: | ||
603 | return ret; | ||
604 | } | ||
605 | |||
606 | int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq) | ||
607 | { | ||
608 | /* sets rf band bits, but does not write them */ | ||
609 | struct tda18271_priv *priv = fe->tuner_priv; | ||
610 | unsigned char *regs = priv->tda18271_regs; | ||
611 | u8 val; | ||
612 | |||
613 | int ret = tda18271_lookup_map(fe, RF_BAND, freq, &val); | ||
614 | if (tda_fail(ret)) | ||
615 | goto fail; | ||
616 | |||
617 | regs[R_EP2] &= ~0xe0; /* clear rf band bits */ | ||
618 | regs[R_EP2] |= (0xe0 & (val << 5)); | ||
619 | fail: | ||
620 | return ret; | ||
621 | } | ||
622 | |||
623 | int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq) | ||
624 | { | ||
625 | /* sets gain taper bits, but does not write them */ | ||
626 | struct tda18271_priv *priv = fe->tuner_priv; | ||
627 | unsigned char *regs = priv->tda18271_regs; | ||
628 | u8 val; | ||
629 | |||
630 | int ret = tda18271_lookup_map(fe, GAIN_TAPER, freq, &val); | ||
631 | if (tda_fail(ret)) | ||
632 | goto fail; | ||
633 | |||
634 | regs[R_EP2] &= ~0x1f; /* clear gain taper bits */ | ||
635 | regs[R_EP2] |= (0x1f & val); | ||
636 | fail: | ||
637 | return ret; | ||
638 | } | ||
639 | |||
640 | int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq) | ||
641 | { | ||
642 | /* sets IR Meas bits, but does not write them */ | ||
643 | struct tda18271_priv *priv = fe->tuner_priv; | ||
644 | unsigned char *regs = priv->tda18271_regs; | ||
645 | u8 val; | ||
646 | |||
647 | int ret = tda18271_lookup_map(fe, IR_MEASURE, freq, &val); | ||
648 | if (tda_fail(ret)) | ||
649 | goto fail; | ||
650 | |||
651 | regs[R_EP5] &= ~0x07; | ||
652 | regs[R_EP5] |= (0x07 & val); | ||
653 | fail: | ||
654 | return ret; | ||
655 | } | ||
656 | |||
657 | int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq) | ||
658 | { | ||
659 | /* sets rf cal byte (RFC_Cprog), but does not write it */ | ||
660 | struct tda18271_priv *priv = fe->tuner_priv; | ||
661 | unsigned char *regs = priv->tda18271_regs; | ||
662 | u8 val; | ||
663 | |||
664 | int ret = tda18271_lookup_map(fe, RF_CAL, freq, &val); | ||
665 | /* The TDA18271HD/C1 rf_cal map lookup is expected to go out of range | ||
666 | * for frequencies above 61.1 MHz. In these cases, the internal RF | ||
667 | * tracking filters calibration mechanism is used. | ||
668 | * | ||
669 | * There is no need to warn the user about this. | ||
670 | */ | ||
671 | if (ret < 0) | ||
672 | goto fail; | ||
673 | |||
674 | regs[R_EB14] = val; | ||
675 | fail: | ||
676 | return ret; | ||
677 | } | ||
678 | |||
679 | int _tda_printk(struct tda18271_priv *state, const char *level, | ||
680 | const char *func, const char *fmt, ...) | ||
681 | { | ||
682 | struct va_format vaf; | ||
683 | va_list args; | ||
684 | int rtn; | ||
685 | |||
686 | va_start(args, fmt); | ||
687 | |||
688 | vaf.fmt = fmt; | ||
689 | vaf.va = &args; | ||
690 | |||
691 | if (state) | ||
692 | rtn = printk("%s%s: [%d-%04x|%c] %pV", | ||
693 | level, func, i2c_adapter_id(state->i2c_props.adap), | ||
694 | state->i2c_props.addr, | ||
695 | (state->role == TDA18271_MASTER) ? 'M' : 'S', | ||
696 | &vaf); | ||
697 | else | ||
698 | rtn = printk("%s%s: %pV", level, func, &vaf); | ||
699 | |||
700 | va_end(args); | ||
701 | |||
702 | return rtn; | ||
703 | } | ||
diff --git a/drivers/media/tuners/tda18271-fe.c b/drivers/media/tuners/tda18271-fe.c new file mode 100644 index 000000000000..2e67f4459904 --- /dev/null +++ b/drivers/media/tuners/tda18271-fe.c | |||
@@ -0,0 +1,1345 @@ | |||
1 | /* | ||
2 | tda18271-fe.c - driver for the Philips / NXP TDA18271 silicon tuner | ||
3 | |||
4 | Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org> | ||
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 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/delay.h> | ||
22 | #include <linux/videodev2.h> | ||
23 | #include "tda18271-priv.h" | ||
24 | |||
25 | int tda18271_debug; | ||
26 | module_param_named(debug, tda18271_debug, int, 0644); | ||
27 | MODULE_PARM_DESC(debug, "set debug level " | ||
28 | "(info=1, map=2, reg=4, adv=8, cal=16 (or-able))"); | ||
29 | |||
30 | static int tda18271_cal_on_startup = -1; | ||
31 | module_param_named(cal, tda18271_cal_on_startup, int, 0644); | ||
32 | MODULE_PARM_DESC(cal, "perform RF tracking filter calibration on startup"); | ||
33 | |||
34 | static DEFINE_MUTEX(tda18271_list_mutex); | ||
35 | static LIST_HEAD(hybrid_tuner_instance_list); | ||
36 | |||
37 | /*---------------------------------------------------------------------*/ | ||
38 | |||
39 | static int tda18271_toggle_output(struct dvb_frontend *fe, int standby) | ||
40 | { | ||
41 | struct tda18271_priv *priv = fe->tuner_priv; | ||
42 | |||
43 | int ret = tda18271_set_standby_mode(fe, standby ? 1 : 0, | ||
44 | priv->output_opt & TDA18271_OUTPUT_LT_OFF ? 1 : 0, | ||
45 | priv->output_opt & TDA18271_OUTPUT_XT_OFF ? 1 : 0); | ||
46 | |||
47 | if (tda_fail(ret)) | ||
48 | goto fail; | ||
49 | |||
50 | tda_dbg("%s mode: xtal oscillator %s, slave tuner loop thru %s\n", | ||
51 | standby ? "standby" : "active", | ||
52 | priv->output_opt & TDA18271_OUTPUT_XT_OFF ? "off" : "on", | ||
53 | priv->output_opt & TDA18271_OUTPUT_LT_OFF ? "off" : "on"); | ||
54 | fail: | ||
55 | return ret; | ||
56 | } | ||
57 | |||
58 | /*---------------------------------------------------------------------*/ | ||
59 | |||
60 | static inline int charge_pump_source(struct dvb_frontend *fe, int force) | ||
61 | { | ||
62 | struct tda18271_priv *priv = fe->tuner_priv; | ||
63 | return tda18271_charge_pump_source(fe, | ||
64 | (priv->role == TDA18271_SLAVE) ? | ||
65 | TDA18271_CAL_PLL : | ||
66 | TDA18271_MAIN_PLL, force); | ||
67 | } | ||
68 | |||
69 | static inline void tda18271_set_if_notch(struct dvb_frontend *fe) | ||
70 | { | ||
71 | struct tda18271_priv *priv = fe->tuner_priv; | ||
72 | unsigned char *regs = priv->tda18271_regs; | ||
73 | |||
74 | switch (priv->mode) { | ||
75 | case TDA18271_ANALOG: | ||
76 | regs[R_MPD] &= ~0x80; /* IF notch = 0 */ | ||
77 | break; | ||
78 | case TDA18271_DIGITAL: | ||
79 | regs[R_MPD] |= 0x80; /* IF notch = 1 */ | ||
80 | break; | ||
81 | } | ||
82 | } | ||
83 | |||
84 | static int tda18271_channel_configuration(struct dvb_frontend *fe, | ||
85 | struct tda18271_std_map_item *map, | ||
86 | u32 freq, u32 bw) | ||
87 | { | ||
88 | struct tda18271_priv *priv = fe->tuner_priv; | ||
89 | unsigned char *regs = priv->tda18271_regs; | ||
90 | int ret; | ||
91 | u32 N; | ||
92 | |||
93 | /* update TV broadcast parameters */ | ||
94 | |||
95 | /* set standard */ | ||
96 | regs[R_EP3] &= ~0x1f; /* clear std bits */ | ||
97 | regs[R_EP3] |= (map->agc_mode << 3) | map->std; | ||
98 | |||
99 | if (priv->id == TDA18271HDC2) { | ||
100 | /* set rfagc to high speed mode */ | ||
101 | regs[R_EP3] &= ~0x04; | ||
102 | } | ||
103 | |||
104 | /* set cal mode to normal */ | ||
105 | regs[R_EP4] &= ~0x03; | ||
106 | |||
107 | /* update IF output level */ | ||
108 | regs[R_EP4] &= ~0x1c; /* clear if level bits */ | ||
109 | regs[R_EP4] |= (map->if_lvl << 2); | ||
110 | |||
111 | /* update FM_RFn */ | ||
112 | regs[R_EP4] &= ~0x80; | ||
113 | regs[R_EP4] |= map->fm_rfn << 7; | ||
114 | |||
115 | /* update rf top / if top */ | ||
116 | regs[R_EB22] = 0x00; | ||
117 | regs[R_EB22] |= map->rfagc_top; | ||
118 | ret = tda18271_write_regs(fe, R_EB22, 1); | ||
119 | if (tda_fail(ret)) | ||
120 | goto fail; | ||
121 | |||
122 | /* --------------------------------------------------------------- */ | ||
123 | |||
124 | /* disable Power Level Indicator */ | ||
125 | regs[R_EP1] |= 0x40; | ||
126 | |||
127 | /* make sure thermometer is off */ | ||
128 | regs[R_TM] &= ~0x10; | ||
129 | |||
130 | /* frequency dependent parameters */ | ||
131 | |||
132 | tda18271_calc_ir_measure(fe, &freq); | ||
133 | |||
134 | tda18271_calc_bp_filter(fe, &freq); | ||
135 | |||
136 | tda18271_calc_rf_band(fe, &freq); | ||
137 | |||
138 | tda18271_calc_gain_taper(fe, &freq); | ||
139 | |||
140 | /* --------------------------------------------------------------- */ | ||
141 | |||
142 | /* dual tuner and agc1 extra configuration */ | ||
143 | |||
144 | switch (priv->role) { | ||
145 | case TDA18271_MASTER: | ||
146 | regs[R_EB1] |= 0x04; /* main vco */ | ||
147 | break; | ||
148 | case TDA18271_SLAVE: | ||
149 | regs[R_EB1] &= ~0x04; /* cal vco */ | ||
150 | break; | ||
151 | } | ||
152 | |||
153 | /* agc1 always active */ | ||
154 | regs[R_EB1] &= ~0x02; | ||
155 | |||
156 | /* agc1 has priority on agc2 */ | ||
157 | regs[R_EB1] &= ~0x01; | ||
158 | |||
159 | ret = tda18271_write_regs(fe, R_EB1, 1); | ||
160 | if (tda_fail(ret)) | ||
161 | goto fail; | ||
162 | |||
163 | /* --------------------------------------------------------------- */ | ||
164 | |||
165 | N = map->if_freq * 1000 + freq; | ||
166 | |||
167 | switch (priv->role) { | ||
168 | case TDA18271_MASTER: | ||
169 | tda18271_calc_main_pll(fe, N); | ||
170 | tda18271_set_if_notch(fe); | ||
171 | tda18271_write_regs(fe, R_MPD, 4); | ||
172 | break; | ||
173 | case TDA18271_SLAVE: | ||
174 | tda18271_calc_cal_pll(fe, N); | ||
175 | tda18271_write_regs(fe, R_CPD, 4); | ||
176 | |||
177 | regs[R_MPD] = regs[R_CPD] & 0x7f; | ||
178 | tda18271_set_if_notch(fe); | ||
179 | tda18271_write_regs(fe, R_MPD, 1); | ||
180 | break; | ||
181 | } | ||
182 | |||
183 | ret = tda18271_write_regs(fe, R_TM, 7); | ||
184 | if (tda_fail(ret)) | ||
185 | goto fail; | ||
186 | |||
187 | /* force charge pump source */ | ||
188 | charge_pump_source(fe, 1); | ||
189 | |||
190 | msleep(1); | ||
191 | |||
192 | /* return pll to normal operation */ | ||
193 | charge_pump_source(fe, 0); | ||
194 | |||
195 | msleep(20); | ||
196 | |||
197 | if (priv->id == TDA18271HDC2) { | ||
198 | /* set rfagc to normal speed mode */ | ||
199 | if (map->fm_rfn) | ||
200 | regs[R_EP3] &= ~0x04; | ||
201 | else | ||
202 | regs[R_EP3] |= 0x04; | ||
203 | ret = tda18271_write_regs(fe, R_EP3, 1); | ||
204 | } | ||
205 | fail: | ||
206 | return ret; | ||
207 | } | ||
208 | |||
209 | static int tda18271_read_thermometer(struct dvb_frontend *fe) | ||
210 | { | ||
211 | struct tda18271_priv *priv = fe->tuner_priv; | ||
212 | unsigned char *regs = priv->tda18271_regs; | ||
213 | int tm; | ||
214 | |||
215 | /* switch thermometer on */ | ||
216 | regs[R_TM] |= 0x10; | ||
217 | tda18271_write_regs(fe, R_TM, 1); | ||
218 | |||
219 | /* read thermometer info */ | ||
220 | tda18271_read_regs(fe); | ||
221 | |||
222 | if ((((regs[R_TM] & 0x0f) == 0x00) && ((regs[R_TM] & 0x20) == 0x20)) || | ||
223 | (((regs[R_TM] & 0x0f) == 0x08) && ((regs[R_TM] & 0x20) == 0x00))) { | ||
224 | |||
225 | if ((regs[R_TM] & 0x20) == 0x20) | ||
226 | regs[R_TM] &= ~0x20; | ||
227 | else | ||
228 | regs[R_TM] |= 0x20; | ||
229 | |||
230 | tda18271_write_regs(fe, R_TM, 1); | ||
231 | |||
232 | msleep(10); /* temperature sensing */ | ||
233 | |||
234 | /* read thermometer info */ | ||
235 | tda18271_read_regs(fe); | ||
236 | } | ||
237 | |||
238 | tm = tda18271_lookup_thermometer(fe); | ||
239 | |||
240 | /* switch thermometer off */ | ||
241 | regs[R_TM] &= ~0x10; | ||
242 | tda18271_write_regs(fe, R_TM, 1); | ||
243 | |||
244 | /* set CAL mode to normal */ | ||
245 | regs[R_EP4] &= ~0x03; | ||
246 | tda18271_write_regs(fe, R_EP4, 1); | ||
247 | |||
248 | return tm; | ||
249 | } | ||
250 | |||
251 | /* ------------------------------------------------------------------ */ | ||
252 | |||
253 | static int tda18271c2_rf_tracking_filters_correction(struct dvb_frontend *fe, | ||
254 | u32 freq) | ||
255 | { | ||
256 | struct tda18271_priv *priv = fe->tuner_priv; | ||
257 | struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state; | ||
258 | unsigned char *regs = priv->tda18271_regs; | ||
259 | int i, ret; | ||
260 | u8 tm_current, dc_over_dt, rf_tab; | ||
261 | s32 rfcal_comp, approx; | ||
262 | |||
263 | /* power up */ | ||
264 | ret = tda18271_set_standby_mode(fe, 0, 0, 0); | ||
265 | if (tda_fail(ret)) | ||
266 | goto fail; | ||
267 | |||
268 | /* read die current temperature */ | ||
269 | tm_current = tda18271_read_thermometer(fe); | ||
270 | |||
271 | /* frequency dependent parameters */ | ||
272 | |||
273 | tda18271_calc_rf_cal(fe, &freq); | ||
274 | rf_tab = regs[R_EB14]; | ||
275 | |||
276 | i = tda18271_lookup_rf_band(fe, &freq, NULL); | ||
277 | if (tda_fail(i)) | ||
278 | return i; | ||
279 | |||
280 | if ((0 == map[i].rf3) || (freq / 1000 < map[i].rf2)) { | ||
281 | approx = map[i].rf_a1 * (s32)(freq / 1000 - map[i].rf1) + | ||
282 | map[i].rf_b1 + rf_tab; | ||
283 | } else { | ||
284 | approx = map[i].rf_a2 * (s32)(freq / 1000 - map[i].rf2) + | ||
285 | map[i].rf_b2 + rf_tab; | ||
286 | } | ||
287 | |||
288 | if (approx < 0) | ||
289 | approx = 0; | ||
290 | if (approx > 255) | ||
291 | approx = 255; | ||
292 | |||
293 | tda18271_lookup_map(fe, RF_CAL_DC_OVER_DT, &freq, &dc_over_dt); | ||
294 | |||
295 | /* calculate temperature compensation */ | ||
296 | rfcal_comp = dc_over_dt * (s32)(tm_current - priv->tm_rfcal) / 1000; | ||
297 | |||
298 | regs[R_EB14] = (unsigned char)(approx + rfcal_comp); | ||
299 | ret = tda18271_write_regs(fe, R_EB14, 1); | ||
300 | fail: | ||
301 | return ret; | ||
302 | } | ||
303 | |||
304 | static int tda18271_por(struct dvb_frontend *fe) | ||
305 | { | ||
306 | struct tda18271_priv *priv = fe->tuner_priv; | ||
307 | unsigned char *regs = priv->tda18271_regs; | ||
308 | int ret; | ||
309 | |||
310 | /* power up detector 1 */ | ||
311 | regs[R_EB12] &= ~0x20; | ||
312 | ret = tda18271_write_regs(fe, R_EB12, 1); | ||
313 | if (tda_fail(ret)) | ||
314 | goto fail; | ||
315 | |||
316 | regs[R_EB18] &= ~0x80; /* turn agc1 loop on */ | ||
317 | regs[R_EB18] &= ~0x03; /* set agc1_gain to 6 dB */ | ||
318 | ret = tda18271_write_regs(fe, R_EB18, 1); | ||
319 | if (tda_fail(ret)) | ||
320 | goto fail; | ||
321 | |||
322 | regs[R_EB21] |= 0x03; /* set agc2_gain to -6 dB */ | ||
323 | |||
324 | /* POR mode */ | ||
325 | ret = tda18271_set_standby_mode(fe, 1, 0, 0); | ||
326 | if (tda_fail(ret)) | ||
327 | goto fail; | ||
328 | |||
329 | /* disable 1.5 MHz low pass filter */ | ||
330 | regs[R_EB23] &= ~0x04; /* forcelp_fc2_en = 0 */ | ||
331 | regs[R_EB23] &= ~0x02; /* XXX: lp_fc[2] = 0 */ | ||
332 | ret = tda18271_write_regs(fe, R_EB21, 3); | ||
333 | fail: | ||
334 | return ret; | ||
335 | } | ||
336 | |||
337 | static int tda18271_calibrate_rf(struct dvb_frontend *fe, u32 freq) | ||
338 | { | ||
339 | struct tda18271_priv *priv = fe->tuner_priv; | ||
340 | unsigned char *regs = priv->tda18271_regs; | ||
341 | u32 N; | ||
342 | |||
343 | /* set CAL mode to normal */ | ||
344 | regs[R_EP4] &= ~0x03; | ||
345 | tda18271_write_regs(fe, R_EP4, 1); | ||
346 | |||
347 | /* switch off agc1 */ | ||
348 | regs[R_EP3] |= 0x40; /* sm_lt = 1 */ | ||
349 | |||
350 | regs[R_EB18] |= 0x03; /* set agc1_gain to 15 dB */ | ||
351 | tda18271_write_regs(fe, R_EB18, 1); | ||
352 | |||
353 | /* frequency dependent parameters */ | ||
354 | |||
355 | tda18271_calc_bp_filter(fe, &freq); | ||
356 | tda18271_calc_gain_taper(fe, &freq); | ||
357 | tda18271_calc_rf_band(fe, &freq); | ||
358 | tda18271_calc_km(fe, &freq); | ||
359 | |||
360 | tda18271_write_regs(fe, R_EP1, 3); | ||
361 | tda18271_write_regs(fe, R_EB13, 1); | ||
362 | |||
363 | /* main pll charge pump source */ | ||
364 | tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 1); | ||
365 | |||
366 | /* cal pll charge pump source */ | ||
367 | tda18271_charge_pump_source(fe, TDA18271_CAL_PLL, 1); | ||
368 | |||
369 | /* force dcdc converter to 0 V */ | ||
370 | regs[R_EB14] = 0x00; | ||
371 | tda18271_write_regs(fe, R_EB14, 1); | ||
372 | |||
373 | /* disable plls lock */ | ||
374 | regs[R_EB20] &= ~0x20; | ||
375 | tda18271_write_regs(fe, R_EB20, 1); | ||
376 | |||
377 | /* set CAL mode to RF tracking filter calibration */ | ||
378 | regs[R_EP4] |= 0x03; | ||
379 | tda18271_write_regs(fe, R_EP4, 2); | ||
380 | |||
381 | /* --------------------------------------------------------------- */ | ||
382 | |||
383 | /* set the internal calibration signal */ | ||
384 | N = freq; | ||
385 | |||
386 | tda18271_calc_cal_pll(fe, N); | ||
387 | tda18271_write_regs(fe, R_CPD, 4); | ||
388 | |||
389 | /* downconvert internal calibration */ | ||
390 | N += 1000000; | ||
391 | |||
392 | tda18271_calc_main_pll(fe, N); | ||
393 | tda18271_write_regs(fe, R_MPD, 4); | ||
394 | |||
395 | msleep(5); | ||
396 | |||
397 | tda18271_write_regs(fe, R_EP2, 1); | ||
398 | tda18271_write_regs(fe, R_EP1, 1); | ||
399 | tda18271_write_regs(fe, R_EP2, 1); | ||
400 | tda18271_write_regs(fe, R_EP1, 1); | ||
401 | |||
402 | /* --------------------------------------------------------------- */ | ||
403 | |||
404 | /* normal operation for the main pll */ | ||
405 | tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 0); | ||
406 | |||
407 | /* normal operation for the cal pll */ | ||
408 | tda18271_charge_pump_source(fe, TDA18271_CAL_PLL, 0); | ||
409 | |||
410 | msleep(10); /* plls locking */ | ||
411 | |||
412 | /* launch the rf tracking filters calibration */ | ||
413 | regs[R_EB20] |= 0x20; | ||
414 | tda18271_write_regs(fe, R_EB20, 1); | ||
415 | |||
416 | msleep(60); /* calibration */ | ||
417 | |||
418 | /* --------------------------------------------------------------- */ | ||
419 | |||
420 | /* set CAL mode to normal */ | ||
421 | regs[R_EP4] &= ~0x03; | ||
422 | |||
423 | /* switch on agc1 */ | ||
424 | regs[R_EP3] &= ~0x40; /* sm_lt = 0 */ | ||
425 | |||
426 | regs[R_EB18] &= ~0x03; /* set agc1_gain to 6 dB */ | ||
427 | tda18271_write_regs(fe, R_EB18, 1); | ||
428 | |||
429 | tda18271_write_regs(fe, R_EP3, 2); | ||
430 | |||
431 | /* synchronization */ | ||
432 | tda18271_write_regs(fe, R_EP1, 1); | ||
433 | |||
434 | /* get calibration result */ | ||
435 | tda18271_read_extended(fe); | ||
436 | |||
437 | return regs[R_EB14]; | ||
438 | } | ||
439 | |||
440 | static int tda18271_powerscan(struct dvb_frontend *fe, | ||
441 | u32 *freq_in, u32 *freq_out) | ||
442 | { | ||
443 | struct tda18271_priv *priv = fe->tuner_priv; | ||
444 | unsigned char *regs = priv->tda18271_regs; | ||
445 | int sgn, bcal, count, wait, ret; | ||
446 | u8 cid_target; | ||
447 | u16 count_limit; | ||
448 | u32 freq; | ||
449 | |||
450 | freq = *freq_in; | ||
451 | |||
452 | tda18271_calc_rf_band(fe, &freq); | ||
453 | tda18271_calc_rf_cal(fe, &freq); | ||
454 | tda18271_calc_gain_taper(fe, &freq); | ||
455 | tda18271_lookup_cid_target(fe, &freq, &cid_target, &count_limit); | ||
456 | |||
457 | tda18271_write_regs(fe, R_EP2, 1); | ||
458 | tda18271_write_regs(fe, R_EB14, 1); | ||
459 | |||
460 | /* downconvert frequency */ | ||
461 | freq += 1000000; | ||
462 | |||
463 | tda18271_calc_main_pll(fe, freq); | ||
464 | tda18271_write_regs(fe, R_MPD, 4); | ||
465 | |||
466 | msleep(5); /* pll locking */ | ||
467 | |||
468 | /* detection mode */ | ||
469 | regs[R_EP4] &= ~0x03; | ||
470 | regs[R_EP4] |= 0x01; | ||
471 | tda18271_write_regs(fe, R_EP4, 1); | ||
472 | |||
473 | /* launch power detection measurement */ | ||
474 | tda18271_write_regs(fe, R_EP2, 1); | ||
475 | |||
476 | /* read power detection info, stored in EB10 */ | ||
477 | ret = tda18271_read_extended(fe); | ||
478 | if (tda_fail(ret)) | ||
479 | return ret; | ||
480 | |||
481 | /* algorithm initialization */ | ||
482 | sgn = 1; | ||
483 | *freq_out = *freq_in; | ||
484 | bcal = 0; | ||
485 | count = 0; | ||
486 | wait = false; | ||
487 | |||
488 | while ((regs[R_EB10] & 0x3f) < cid_target) { | ||
489 | /* downconvert updated freq to 1 MHz */ | ||
490 | freq = *freq_in + (sgn * count) + 1000000; | ||
491 | |||
492 | tda18271_calc_main_pll(fe, freq); | ||
493 | tda18271_write_regs(fe, R_MPD, 4); | ||
494 | |||
495 | if (wait) { | ||
496 | msleep(5); /* pll locking */ | ||
497 | wait = false; | ||
498 | } else | ||
499 | udelay(100); /* pll locking */ | ||
500 | |||
501 | /* launch power detection measurement */ | ||
502 | tda18271_write_regs(fe, R_EP2, 1); | ||
503 | |||
504 | /* read power detection info, stored in EB10 */ | ||
505 | ret = tda18271_read_extended(fe); | ||
506 | if (tda_fail(ret)) | ||
507 | return ret; | ||
508 | |||
509 | count += 200; | ||
510 | |||
511 | if (count <= count_limit) | ||
512 | continue; | ||
513 | |||
514 | if (sgn <= 0) | ||
515 | break; | ||
516 | |||
517 | sgn = -1 * sgn; | ||
518 | count = 200; | ||
519 | wait = true; | ||
520 | } | ||
521 | |||
522 | if ((regs[R_EB10] & 0x3f) >= cid_target) { | ||
523 | bcal = 1; | ||
524 | *freq_out = freq - 1000000; | ||
525 | } else | ||
526 | bcal = 0; | ||
527 | |||
528 | tda_cal("bcal = %d, freq_in = %d, freq_out = %d (freq = %d)\n", | ||
529 | bcal, *freq_in, *freq_out, freq); | ||
530 | |||
531 | return bcal; | ||
532 | } | ||
533 | |||
534 | static int tda18271_powerscan_init(struct dvb_frontend *fe) | ||
535 | { | ||
536 | struct tda18271_priv *priv = fe->tuner_priv; | ||
537 | unsigned char *regs = priv->tda18271_regs; | ||
538 | int ret; | ||
539 | |||
540 | /* set standard to digital */ | ||
541 | regs[R_EP3] &= ~0x1f; /* clear std bits */ | ||
542 | regs[R_EP3] |= 0x12; | ||
543 | |||
544 | /* set cal mode to normal */ | ||
545 | regs[R_EP4] &= ~0x03; | ||
546 | |||
547 | /* update IF output level */ | ||
548 | regs[R_EP4] &= ~0x1c; /* clear if level bits */ | ||
549 | |||
550 | ret = tda18271_write_regs(fe, R_EP3, 2); | ||
551 | if (tda_fail(ret)) | ||
552 | goto fail; | ||
553 | |||
554 | regs[R_EB18] &= ~0x03; /* set agc1_gain to 6 dB */ | ||
555 | ret = tda18271_write_regs(fe, R_EB18, 1); | ||
556 | if (tda_fail(ret)) | ||
557 | goto fail; | ||
558 | |||
559 | regs[R_EB21] &= ~0x03; /* set agc2_gain to -15 dB */ | ||
560 | |||
561 | /* 1.5 MHz low pass filter */ | ||
562 | regs[R_EB23] |= 0x04; /* forcelp_fc2_en = 1 */ | ||
563 | regs[R_EB23] |= 0x02; /* lp_fc[2] = 1 */ | ||
564 | |||
565 | ret = tda18271_write_regs(fe, R_EB21, 3); | ||
566 | fail: | ||
567 | return ret; | ||
568 | } | ||
569 | |||
570 | static int tda18271_rf_tracking_filters_init(struct dvb_frontend *fe, u32 freq) | ||
571 | { | ||
572 | struct tda18271_priv *priv = fe->tuner_priv; | ||
573 | struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state; | ||
574 | unsigned char *regs = priv->tda18271_regs; | ||
575 | int bcal, rf, i; | ||
576 | s32 divisor, dividend; | ||
577 | #define RF1 0 | ||
578 | #define RF2 1 | ||
579 | #define RF3 2 | ||
580 | u32 rf_default[3]; | ||
581 | u32 rf_freq[3]; | ||
582 | s32 prog_cal[3]; | ||
583 | s32 prog_tab[3]; | ||
584 | |||
585 | i = tda18271_lookup_rf_band(fe, &freq, NULL); | ||
586 | |||
587 | if (tda_fail(i)) | ||
588 | return i; | ||
589 | |||
590 | rf_default[RF1] = 1000 * map[i].rf1_def; | ||
591 | rf_default[RF2] = 1000 * map[i].rf2_def; | ||
592 | rf_default[RF3] = 1000 * map[i].rf3_def; | ||
593 | |||
594 | for (rf = RF1; rf <= RF3; rf++) { | ||
595 | if (0 == rf_default[rf]) | ||
596 | return 0; | ||
597 | tda_cal("freq = %d, rf = %d\n", freq, rf); | ||
598 | |||
599 | /* look for optimized calibration frequency */ | ||
600 | bcal = tda18271_powerscan(fe, &rf_default[rf], &rf_freq[rf]); | ||
601 | if (tda_fail(bcal)) | ||
602 | return bcal; | ||
603 | |||
604 | tda18271_calc_rf_cal(fe, &rf_freq[rf]); | ||
605 | prog_tab[rf] = (s32)regs[R_EB14]; | ||
606 | |||
607 | if (1 == bcal) | ||
608 | prog_cal[rf] = | ||
609 | (s32)tda18271_calibrate_rf(fe, rf_freq[rf]); | ||
610 | else | ||
611 | prog_cal[rf] = prog_tab[rf]; | ||
612 | |||
613 | switch (rf) { | ||
614 | case RF1: | ||
615 | map[i].rf_a1 = 0; | ||
616 | map[i].rf_b1 = (prog_cal[RF1] - prog_tab[RF1]); | ||
617 | map[i].rf1 = rf_freq[RF1] / 1000; | ||
618 | break; | ||
619 | case RF2: | ||
620 | dividend = (prog_cal[RF2] - prog_tab[RF2] - | ||
621 | prog_cal[RF1] + prog_tab[RF1]); | ||
622 | divisor = (s32)(rf_freq[RF2] - rf_freq[RF1]) / 1000; | ||
623 | map[i].rf_a1 = (dividend / divisor); | ||
624 | map[i].rf2 = rf_freq[RF2] / 1000; | ||
625 | break; | ||
626 | case RF3: | ||
627 | dividend = (prog_cal[RF3] - prog_tab[RF3] - | ||
628 | prog_cal[RF2] + prog_tab[RF2]); | ||
629 | divisor = (s32)(rf_freq[RF3] - rf_freq[RF2]) / 1000; | ||
630 | map[i].rf_a2 = (dividend / divisor); | ||
631 | map[i].rf_b2 = (prog_cal[RF2] - prog_tab[RF2]); | ||
632 | map[i].rf3 = rf_freq[RF3] / 1000; | ||
633 | break; | ||
634 | default: | ||
635 | BUG(); | ||
636 | } | ||
637 | } | ||
638 | |||
639 | return 0; | ||
640 | } | ||
641 | |||
642 | static int tda18271_calc_rf_filter_curve(struct dvb_frontend *fe) | ||
643 | { | ||
644 | struct tda18271_priv *priv = fe->tuner_priv; | ||
645 | unsigned int i; | ||
646 | int ret; | ||
647 | |||
648 | tda_info("tda18271: performing RF tracking filter calibration\n"); | ||
649 | |||
650 | /* wait for die temperature stabilization */ | ||
651 | msleep(200); | ||
652 | |||
653 | ret = tda18271_powerscan_init(fe); | ||
654 | if (tda_fail(ret)) | ||
655 | goto fail; | ||
656 | |||
657 | /* rf band calibration */ | ||
658 | for (i = 0; priv->rf_cal_state[i].rfmax != 0; i++) { | ||
659 | ret = | ||
660 | tda18271_rf_tracking_filters_init(fe, 1000 * | ||
661 | priv->rf_cal_state[i].rfmax); | ||
662 | if (tda_fail(ret)) | ||
663 | goto fail; | ||
664 | } | ||
665 | |||
666 | priv->tm_rfcal = tda18271_read_thermometer(fe); | ||
667 | fail: | ||
668 | return ret; | ||
669 | } | ||
670 | |||
671 | /* ------------------------------------------------------------------ */ | ||
672 | |||
673 | static int tda18271c2_rf_cal_init(struct dvb_frontend *fe) | ||
674 | { | ||
675 | struct tda18271_priv *priv = fe->tuner_priv; | ||
676 | unsigned char *regs = priv->tda18271_regs; | ||
677 | int ret; | ||
678 | |||
679 | /* test RF_CAL_OK to see if we need init */ | ||
680 | if ((regs[R_EP1] & 0x10) == 0) | ||
681 | priv->cal_initialized = false; | ||
682 | |||
683 | if (priv->cal_initialized) | ||
684 | return 0; | ||
685 | |||
686 | ret = tda18271_calc_rf_filter_curve(fe); | ||
687 | if (tda_fail(ret)) | ||
688 | goto fail; | ||
689 | |||
690 | ret = tda18271_por(fe); | ||
691 | if (tda_fail(ret)) | ||
692 | goto fail; | ||
693 | |||
694 | tda_info("tda18271: RF tracking filter calibration complete\n"); | ||
695 | |||
696 | priv->cal_initialized = true; | ||
697 | goto end; | ||
698 | fail: | ||
699 | tda_info("tda18271: RF tracking filter calibration failed!\n"); | ||
700 | end: | ||
701 | return ret; | ||
702 | } | ||
703 | |||
704 | static int tda18271c1_rf_tracking_filter_calibration(struct dvb_frontend *fe, | ||
705 | u32 freq, u32 bw) | ||
706 | { | ||
707 | struct tda18271_priv *priv = fe->tuner_priv; | ||
708 | unsigned char *regs = priv->tda18271_regs; | ||
709 | int ret; | ||
710 | u32 N = 0; | ||
711 | |||
712 | /* calculate bp filter */ | ||
713 | tda18271_calc_bp_filter(fe, &freq); | ||
714 | tda18271_write_regs(fe, R_EP1, 1); | ||
715 | |||
716 | regs[R_EB4] &= 0x07; | ||
717 | regs[R_EB4] |= 0x60; | ||
718 | tda18271_write_regs(fe, R_EB4, 1); | ||
719 | |||
720 | regs[R_EB7] = 0x60; | ||
721 | tda18271_write_regs(fe, R_EB7, 1); | ||
722 | |||
723 | regs[R_EB14] = 0x00; | ||
724 | tda18271_write_regs(fe, R_EB14, 1); | ||
725 | |||
726 | regs[R_EB20] = 0xcc; | ||
727 | tda18271_write_regs(fe, R_EB20, 1); | ||
728 | |||
729 | /* set cal mode to RF tracking filter calibration */ | ||
730 | regs[R_EP4] |= 0x03; | ||
731 | |||
732 | /* calculate cal pll */ | ||
733 | |||
734 | switch (priv->mode) { | ||
735 | case TDA18271_ANALOG: | ||
736 | N = freq - 1250000; | ||
737 | break; | ||
738 | case TDA18271_DIGITAL: | ||
739 | N = freq + bw / 2; | ||
740 | break; | ||
741 | } | ||
742 | |||
743 | tda18271_calc_cal_pll(fe, N); | ||
744 | |||
745 | /* calculate main pll */ | ||
746 | |||
747 | switch (priv->mode) { | ||
748 | case TDA18271_ANALOG: | ||
749 | N = freq - 250000; | ||
750 | break; | ||
751 | case TDA18271_DIGITAL: | ||
752 | N = freq + bw / 2 + 1000000; | ||
753 | break; | ||
754 | } | ||
755 | |||
756 | tda18271_calc_main_pll(fe, N); | ||
757 | |||
758 | ret = tda18271_write_regs(fe, R_EP3, 11); | ||
759 | if (tda_fail(ret)) | ||
760 | return ret; | ||
761 | |||
762 | msleep(5); /* RF tracking filter calibration initialization */ | ||
763 | |||
764 | /* search for K,M,CO for RF calibration */ | ||
765 | tda18271_calc_km(fe, &freq); | ||
766 | tda18271_write_regs(fe, R_EB13, 1); | ||
767 | |||
768 | /* search for rf band */ | ||
769 | tda18271_calc_rf_band(fe, &freq); | ||
770 | |||
771 | /* search for gain taper */ | ||
772 | tda18271_calc_gain_taper(fe, &freq); | ||
773 | |||
774 | tda18271_write_regs(fe, R_EP2, 1); | ||
775 | tda18271_write_regs(fe, R_EP1, 1); | ||
776 | tda18271_write_regs(fe, R_EP2, 1); | ||
777 | tda18271_write_regs(fe, R_EP1, 1); | ||
778 | |||
779 | regs[R_EB4] &= 0x07; | ||
780 | regs[R_EB4] |= 0x40; | ||
781 | tda18271_write_regs(fe, R_EB4, 1); | ||
782 | |||
783 | regs[R_EB7] = 0x40; | ||
784 | tda18271_write_regs(fe, R_EB7, 1); | ||
785 | msleep(10); /* pll locking */ | ||
786 | |||
787 | regs[R_EB20] = 0xec; | ||
788 | tda18271_write_regs(fe, R_EB20, 1); | ||
789 | msleep(60); /* RF tracking filter calibration completion */ | ||
790 | |||
791 | regs[R_EP4] &= ~0x03; /* set cal mode to normal */ | ||
792 | tda18271_write_regs(fe, R_EP4, 1); | ||
793 | |||
794 | tda18271_write_regs(fe, R_EP1, 1); | ||
795 | |||
796 | /* RF tracking filter correction for VHF_Low band */ | ||
797 | if (0 == tda18271_calc_rf_cal(fe, &freq)) | ||
798 | tda18271_write_regs(fe, R_EB14, 1); | ||
799 | |||
800 | return 0; | ||
801 | } | ||
802 | |||
803 | /* ------------------------------------------------------------------ */ | ||
804 | |||
805 | static int tda18271_ir_cal_init(struct dvb_frontend *fe) | ||
806 | { | ||
807 | struct tda18271_priv *priv = fe->tuner_priv; | ||
808 | unsigned char *regs = priv->tda18271_regs; | ||
809 | int ret; | ||
810 | |||
811 | ret = tda18271_read_regs(fe); | ||
812 | if (tda_fail(ret)) | ||
813 | goto fail; | ||
814 | |||
815 | /* test IR_CAL_OK to see if we need init */ | ||
816 | if ((regs[R_EP1] & 0x08) == 0) | ||
817 | ret = tda18271_init_regs(fe); | ||
818 | fail: | ||
819 | return ret; | ||
820 | } | ||
821 | |||
822 | static int tda18271_init(struct dvb_frontend *fe) | ||
823 | { | ||
824 | struct tda18271_priv *priv = fe->tuner_priv; | ||
825 | int ret; | ||
826 | |||
827 | mutex_lock(&priv->lock); | ||
828 | |||
829 | /* full power up */ | ||
830 | ret = tda18271_set_standby_mode(fe, 0, 0, 0); | ||
831 | if (tda_fail(ret)) | ||
832 | goto fail; | ||
833 | |||
834 | /* initialization */ | ||
835 | ret = tda18271_ir_cal_init(fe); | ||
836 | if (tda_fail(ret)) | ||
837 | goto fail; | ||
838 | |||
839 | if (priv->id == TDA18271HDC2) | ||
840 | tda18271c2_rf_cal_init(fe); | ||
841 | fail: | ||
842 | mutex_unlock(&priv->lock); | ||
843 | |||
844 | return ret; | ||
845 | } | ||
846 | |||
847 | static int tda18271_sleep(struct dvb_frontend *fe) | ||
848 | { | ||
849 | struct tda18271_priv *priv = fe->tuner_priv; | ||
850 | int ret; | ||
851 | |||
852 | mutex_lock(&priv->lock); | ||
853 | |||
854 | /* enter standby mode, with required output features enabled */ | ||
855 | ret = tda18271_toggle_output(fe, 1); | ||
856 | |||
857 | mutex_unlock(&priv->lock); | ||
858 | |||
859 | return ret; | ||
860 | } | ||
861 | |||
862 | /* ------------------------------------------------------------------ */ | ||
863 | |||
864 | static int tda18271_agc(struct dvb_frontend *fe) | ||
865 | { | ||
866 | struct tda18271_priv *priv = fe->tuner_priv; | ||
867 | int ret = 0; | ||
868 | |||
869 | switch (priv->config) { | ||
870 | case 0: | ||
871 | /* no external agc configuration required */ | ||
872 | if (tda18271_debug & DBG_ADV) | ||
873 | tda_dbg("no agc configuration provided\n"); | ||
874 | break; | ||
875 | case 3: | ||
876 | /* switch with GPIO of saa713x */ | ||
877 | tda_dbg("invoking callback\n"); | ||
878 | if (fe->callback) | ||
879 | ret = fe->callback(priv->i2c_props.adap->algo_data, | ||
880 | DVB_FRONTEND_COMPONENT_TUNER, | ||
881 | TDA18271_CALLBACK_CMD_AGC_ENABLE, | ||
882 | priv->mode); | ||
883 | break; | ||
884 | case 1: | ||
885 | case 2: | ||
886 | default: | ||
887 | /* n/a - currently not supported */ | ||
888 | tda_err("unsupported configuration: %d\n", priv->config); | ||
889 | ret = -EINVAL; | ||
890 | break; | ||
891 | } | ||
892 | return ret; | ||
893 | } | ||
894 | |||
895 | static int tda18271_tune(struct dvb_frontend *fe, | ||
896 | struct tda18271_std_map_item *map, u32 freq, u32 bw) | ||
897 | { | ||
898 | struct tda18271_priv *priv = fe->tuner_priv; | ||
899 | int ret; | ||
900 | |||
901 | tda_dbg("freq = %d, ifc = %d, bw = %d, agc_mode = %d, std = %d\n", | ||
902 | freq, map->if_freq, bw, map->agc_mode, map->std); | ||
903 | |||
904 | ret = tda18271_agc(fe); | ||
905 | if (tda_fail(ret)) | ||
906 | tda_warn("failed to configure agc\n"); | ||
907 | |||
908 | ret = tda18271_init(fe); | ||
909 | if (tda_fail(ret)) | ||
910 | goto fail; | ||
911 | |||
912 | mutex_lock(&priv->lock); | ||
913 | |||
914 | switch (priv->id) { | ||
915 | case TDA18271HDC1: | ||
916 | tda18271c1_rf_tracking_filter_calibration(fe, freq, bw); | ||
917 | break; | ||
918 | case TDA18271HDC2: | ||
919 | tda18271c2_rf_tracking_filters_correction(fe, freq); | ||
920 | break; | ||
921 | } | ||
922 | ret = tda18271_channel_configuration(fe, map, freq, bw); | ||
923 | |||
924 | mutex_unlock(&priv->lock); | ||
925 | fail: | ||
926 | return ret; | ||
927 | } | ||
928 | |||
929 | /* ------------------------------------------------------------------ */ | ||
930 | |||
931 | static int tda18271_set_params(struct dvb_frontend *fe) | ||
932 | { | ||
933 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
934 | u32 delsys = c->delivery_system; | ||
935 | u32 bw = c->bandwidth_hz; | ||
936 | u32 freq = c->frequency; | ||
937 | struct tda18271_priv *priv = fe->tuner_priv; | ||
938 | struct tda18271_std_map *std_map = &priv->std; | ||
939 | struct tda18271_std_map_item *map; | ||
940 | int ret; | ||
941 | |||
942 | priv->mode = TDA18271_DIGITAL; | ||
943 | |||
944 | switch (delsys) { | ||
945 | case SYS_ATSC: | ||
946 | map = &std_map->atsc_6; | ||
947 | bw = 6000000; | ||
948 | break; | ||
949 | case SYS_ISDBT: | ||
950 | case SYS_DVBT: | ||
951 | case SYS_DVBT2: | ||
952 | if (bw <= 6000000) { | ||
953 | map = &std_map->dvbt_6; | ||
954 | } else if (bw <= 7000000) { | ||
955 | map = &std_map->dvbt_7; | ||
956 | } else { | ||
957 | map = &std_map->dvbt_8; | ||
958 | } | ||
959 | break; | ||
960 | case SYS_DVBC_ANNEX_B: | ||
961 | bw = 6000000; | ||
962 | /* falltrough */ | ||
963 | case SYS_DVBC_ANNEX_A: | ||
964 | case SYS_DVBC_ANNEX_C: | ||
965 | if (bw <= 6000000) { | ||
966 | map = &std_map->qam_6; | ||
967 | } else if (bw <= 7000000) { | ||
968 | map = &std_map->qam_7; | ||
969 | } else { | ||
970 | map = &std_map->qam_8; | ||
971 | } | ||
972 | break; | ||
973 | default: | ||
974 | tda_warn("modulation type not supported!\n"); | ||
975 | return -EINVAL; | ||
976 | } | ||
977 | |||
978 | /* When tuning digital, the analog demod must be tri-stated */ | ||
979 | if (fe->ops.analog_ops.standby) | ||
980 | fe->ops.analog_ops.standby(fe); | ||
981 | |||
982 | ret = tda18271_tune(fe, map, freq, bw); | ||
983 | |||
984 | if (tda_fail(ret)) | ||
985 | goto fail; | ||
986 | |||
987 | priv->if_freq = map->if_freq; | ||
988 | priv->frequency = freq; | ||
989 | priv->bandwidth = bw; | ||
990 | fail: | ||
991 | return ret; | ||
992 | } | ||
993 | |||
994 | static int tda18271_set_analog_params(struct dvb_frontend *fe, | ||
995 | struct analog_parameters *params) | ||
996 | { | ||
997 | struct tda18271_priv *priv = fe->tuner_priv; | ||
998 | struct tda18271_std_map *std_map = &priv->std; | ||
999 | struct tda18271_std_map_item *map; | ||
1000 | char *mode; | ||
1001 | int ret; | ||
1002 | u32 freq = params->frequency * 125 * | ||
1003 | ((params->mode == V4L2_TUNER_RADIO) ? 1 : 1000) / 2; | ||
1004 | |||
1005 | priv->mode = TDA18271_ANALOG; | ||
1006 | |||
1007 | if (params->mode == V4L2_TUNER_RADIO) { | ||
1008 | map = &std_map->fm_radio; | ||
1009 | mode = "fm"; | ||
1010 | } else if (params->std & V4L2_STD_MN) { | ||
1011 | map = &std_map->atv_mn; | ||
1012 | mode = "MN"; | ||
1013 | } else if (params->std & V4L2_STD_B) { | ||
1014 | map = &std_map->atv_b; | ||
1015 | mode = "B"; | ||
1016 | } else if (params->std & V4L2_STD_GH) { | ||
1017 | map = &std_map->atv_gh; | ||
1018 | mode = "GH"; | ||
1019 | } else if (params->std & V4L2_STD_PAL_I) { | ||
1020 | map = &std_map->atv_i; | ||
1021 | mode = "I"; | ||
1022 | } else if (params->std & V4L2_STD_DK) { | ||
1023 | map = &std_map->atv_dk; | ||
1024 | mode = "DK"; | ||
1025 | } else if (params->std & V4L2_STD_SECAM_L) { | ||
1026 | map = &std_map->atv_l; | ||
1027 | mode = "L"; | ||
1028 | } else if (params->std & V4L2_STD_SECAM_LC) { | ||
1029 | map = &std_map->atv_lc; | ||
1030 | mode = "L'"; | ||
1031 | } else { | ||
1032 | map = &std_map->atv_i; | ||
1033 | mode = "xx"; | ||
1034 | } | ||
1035 | |||
1036 | tda_dbg("setting tda18271 to system %s\n", mode); | ||
1037 | |||
1038 | ret = tda18271_tune(fe, map, freq, 0); | ||
1039 | |||
1040 | if (tda_fail(ret)) | ||
1041 | goto fail; | ||
1042 | |||
1043 | priv->if_freq = map->if_freq; | ||
1044 | priv->frequency = freq; | ||
1045 | priv->bandwidth = 0; | ||
1046 | fail: | ||
1047 | return ret; | ||
1048 | } | ||
1049 | |||
1050 | static int tda18271_release(struct dvb_frontend *fe) | ||
1051 | { | ||
1052 | struct tda18271_priv *priv = fe->tuner_priv; | ||
1053 | |||
1054 | mutex_lock(&tda18271_list_mutex); | ||
1055 | |||
1056 | if (priv) | ||
1057 | hybrid_tuner_release_state(priv); | ||
1058 | |||
1059 | mutex_unlock(&tda18271_list_mutex); | ||
1060 | |||
1061 | fe->tuner_priv = NULL; | ||
1062 | |||
1063 | return 0; | ||
1064 | } | ||
1065 | |||
1066 | static int tda18271_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
1067 | { | ||
1068 | struct tda18271_priv *priv = fe->tuner_priv; | ||
1069 | *frequency = priv->frequency; | ||
1070 | return 0; | ||
1071 | } | ||
1072 | |||
1073 | static int tda18271_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) | ||
1074 | { | ||
1075 | struct tda18271_priv *priv = fe->tuner_priv; | ||
1076 | *bandwidth = priv->bandwidth; | ||
1077 | return 0; | ||
1078 | } | ||
1079 | |||
1080 | static int tda18271_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
1081 | { | ||
1082 | struct tda18271_priv *priv = fe->tuner_priv; | ||
1083 | *frequency = (u32)priv->if_freq * 1000; | ||
1084 | return 0; | ||
1085 | } | ||
1086 | |||
1087 | /* ------------------------------------------------------------------ */ | ||
1088 | |||
1089 | #define tda18271_update_std(std_cfg, name) do { \ | ||
1090 | if (map->std_cfg.if_freq + \ | ||
1091 | map->std_cfg.agc_mode + map->std_cfg.std + \ | ||
1092 | map->std_cfg.if_lvl + map->std_cfg.rfagc_top > 0) { \ | ||
1093 | tda_dbg("Using custom std config for %s\n", name); \ | ||
1094 | memcpy(&std->std_cfg, &map->std_cfg, \ | ||
1095 | sizeof(struct tda18271_std_map_item)); \ | ||
1096 | } } while (0) | ||
1097 | |||
1098 | #define tda18271_dump_std_item(std_cfg, name) do { \ | ||
1099 | tda_dbg("(%s) if_freq = %d, agc_mode = %d, std = %d, " \ | ||
1100 | "if_lvl = %d, rfagc_top = 0x%02x\n", \ | ||
1101 | name, std->std_cfg.if_freq, \ | ||
1102 | std->std_cfg.agc_mode, std->std_cfg.std, \ | ||
1103 | std->std_cfg.if_lvl, std->std_cfg.rfagc_top); \ | ||
1104 | } while (0) | ||
1105 | |||
1106 | static int tda18271_dump_std_map(struct dvb_frontend *fe) | ||
1107 | { | ||
1108 | struct tda18271_priv *priv = fe->tuner_priv; | ||
1109 | struct tda18271_std_map *std = &priv->std; | ||
1110 | |||
1111 | tda_dbg("========== STANDARD MAP SETTINGS ==========\n"); | ||
1112 | tda18271_dump_std_item(fm_radio, " fm "); | ||
1113 | tda18271_dump_std_item(atv_b, "atv b "); | ||
1114 | tda18271_dump_std_item(atv_dk, "atv dk"); | ||
1115 | tda18271_dump_std_item(atv_gh, "atv gh"); | ||
1116 | tda18271_dump_std_item(atv_i, "atv i "); | ||
1117 | tda18271_dump_std_item(atv_l, "atv l "); | ||
1118 | tda18271_dump_std_item(atv_lc, "atv l'"); | ||
1119 | tda18271_dump_std_item(atv_mn, "atv mn"); | ||
1120 | tda18271_dump_std_item(atsc_6, "atsc 6"); | ||
1121 | tda18271_dump_std_item(dvbt_6, "dvbt 6"); | ||
1122 | tda18271_dump_std_item(dvbt_7, "dvbt 7"); | ||
1123 | tda18271_dump_std_item(dvbt_8, "dvbt 8"); | ||
1124 | tda18271_dump_std_item(qam_6, "qam 6 "); | ||
1125 | tda18271_dump_std_item(qam_8, "qam 8 "); | ||
1126 | |||
1127 | return 0; | ||
1128 | } | ||
1129 | |||
1130 | static int tda18271_update_std_map(struct dvb_frontend *fe, | ||
1131 | struct tda18271_std_map *map) | ||
1132 | { | ||
1133 | struct tda18271_priv *priv = fe->tuner_priv; | ||
1134 | struct tda18271_std_map *std = &priv->std; | ||
1135 | |||
1136 | if (!map) | ||
1137 | return -EINVAL; | ||
1138 | |||
1139 | tda18271_update_std(fm_radio, "fm"); | ||
1140 | tda18271_update_std(atv_b, "atv b"); | ||
1141 | tda18271_update_std(atv_dk, "atv dk"); | ||
1142 | tda18271_update_std(atv_gh, "atv gh"); | ||
1143 | tda18271_update_std(atv_i, "atv i"); | ||
1144 | tda18271_update_std(atv_l, "atv l"); | ||
1145 | tda18271_update_std(atv_lc, "atv l'"); | ||
1146 | tda18271_update_std(atv_mn, "atv mn"); | ||
1147 | tda18271_update_std(atsc_6, "atsc 6"); | ||
1148 | tda18271_update_std(dvbt_6, "dvbt 6"); | ||
1149 | tda18271_update_std(dvbt_7, "dvbt 7"); | ||
1150 | tda18271_update_std(dvbt_8, "dvbt 8"); | ||
1151 | tda18271_update_std(qam_6, "qam 6"); | ||
1152 | tda18271_update_std(qam_8, "qam 8"); | ||
1153 | |||
1154 | return 0; | ||
1155 | } | ||
1156 | |||
1157 | static int tda18271_get_id(struct dvb_frontend *fe) | ||
1158 | { | ||
1159 | struct tda18271_priv *priv = fe->tuner_priv; | ||
1160 | unsigned char *regs = priv->tda18271_regs; | ||
1161 | char *name; | ||
1162 | |||
1163 | mutex_lock(&priv->lock); | ||
1164 | tda18271_read_regs(fe); | ||
1165 | mutex_unlock(&priv->lock); | ||
1166 | |||
1167 | switch (regs[R_ID] & 0x7f) { | ||
1168 | case 3: | ||
1169 | name = "TDA18271HD/C1"; | ||
1170 | priv->id = TDA18271HDC1; | ||
1171 | break; | ||
1172 | case 4: | ||
1173 | name = "TDA18271HD/C2"; | ||
1174 | priv->id = TDA18271HDC2; | ||
1175 | break; | ||
1176 | default: | ||
1177 | tda_info("Unknown device (%i) detected @ %d-%04x, device not supported.\n", | ||
1178 | regs[R_ID], i2c_adapter_id(priv->i2c_props.adap), | ||
1179 | priv->i2c_props.addr); | ||
1180 | return -EINVAL; | ||
1181 | } | ||
1182 | |||
1183 | tda_info("%s detected @ %d-%04x\n", name, | ||
1184 | i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr); | ||
1185 | |||
1186 | return 0; | ||
1187 | } | ||
1188 | |||
1189 | static int tda18271_setup_configuration(struct dvb_frontend *fe, | ||
1190 | struct tda18271_config *cfg) | ||
1191 | { | ||
1192 | struct tda18271_priv *priv = fe->tuner_priv; | ||
1193 | |||
1194 | priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO; | ||
1195 | priv->role = (cfg) ? cfg->role : TDA18271_MASTER; | ||
1196 | priv->config = (cfg) ? cfg->config : 0; | ||
1197 | priv->small_i2c = (cfg) ? | ||
1198 | cfg->small_i2c : TDA18271_39_BYTE_CHUNK_INIT; | ||
1199 | priv->output_opt = (cfg) ? | ||
1200 | cfg->output_opt : TDA18271_OUTPUT_LT_XT_ON; | ||
1201 | |||
1202 | return 0; | ||
1203 | } | ||
1204 | |||
1205 | static inline int tda18271_need_cal_on_startup(struct tda18271_config *cfg) | ||
1206 | { | ||
1207 | /* tda18271_cal_on_startup == -1 when cal module option is unset */ | ||
1208 | return ((tda18271_cal_on_startup == -1) ? | ||
1209 | /* honor configuration setting */ | ||
1210 | ((cfg) && (cfg->rf_cal_on_startup)) : | ||
1211 | /* module option overrides configuration setting */ | ||
1212 | (tda18271_cal_on_startup)) ? 1 : 0; | ||
1213 | } | ||
1214 | |||
1215 | static int tda18271_set_config(struct dvb_frontend *fe, void *priv_cfg) | ||
1216 | { | ||
1217 | struct tda18271_config *cfg = (struct tda18271_config *) priv_cfg; | ||
1218 | |||
1219 | tda18271_setup_configuration(fe, cfg); | ||
1220 | |||
1221 | if (tda18271_need_cal_on_startup(cfg)) | ||
1222 | tda18271_init(fe); | ||
1223 | |||
1224 | /* override default std map with values in config struct */ | ||
1225 | if ((cfg) && (cfg->std_map)) | ||
1226 | tda18271_update_std_map(fe, cfg->std_map); | ||
1227 | |||
1228 | return 0; | ||
1229 | } | ||
1230 | |||
1231 | static const struct dvb_tuner_ops tda18271_tuner_ops = { | ||
1232 | .info = { | ||
1233 | .name = "NXP TDA18271HD", | ||
1234 | .frequency_min = 45000000, | ||
1235 | .frequency_max = 864000000, | ||
1236 | .frequency_step = 62500 | ||
1237 | }, | ||
1238 | .init = tda18271_init, | ||
1239 | .sleep = tda18271_sleep, | ||
1240 | .set_params = tda18271_set_params, | ||
1241 | .set_analog_params = tda18271_set_analog_params, | ||
1242 | .release = tda18271_release, | ||
1243 | .set_config = tda18271_set_config, | ||
1244 | .get_frequency = tda18271_get_frequency, | ||
1245 | .get_bandwidth = tda18271_get_bandwidth, | ||
1246 | .get_if_frequency = tda18271_get_if_frequency, | ||
1247 | }; | ||
1248 | |||
1249 | struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, | ||
1250 | struct i2c_adapter *i2c, | ||
1251 | struct tda18271_config *cfg) | ||
1252 | { | ||
1253 | struct tda18271_priv *priv = NULL; | ||
1254 | int instance, ret; | ||
1255 | |||
1256 | mutex_lock(&tda18271_list_mutex); | ||
1257 | |||
1258 | instance = hybrid_tuner_request_state(struct tda18271_priv, priv, | ||
1259 | hybrid_tuner_instance_list, | ||
1260 | i2c, addr, "tda18271"); | ||
1261 | switch (instance) { | ||
1262 | case 0: | ||
1263 | goto fail; | ||
1264 | case 1: | ||
1265 | /* new tuner instance */ | ||
1266 | fe->tuner_priv = priv; | ||
1267 | |||
1268 | tda18271_setup_configuration(fe, cfg); | ||
1269 | |||
1270 | priv->cal_initialized = false; | ||
1271 | mutex_init(&priv->lock); | ||
1272 | |||
1273 | ret = tda18271_get_id(fe); | ||
1274 | if (tda_fail(ret)) | ||
1275 | goto fail; | ||
1276 | |||
1277 | ret = tda18271_assign_map_layout(fe); | ||
1278 | if (tda_fail(ret)) | ||
1279 | goto fail; | ||
1280 | |||
1281 | mutex_lock(&priv->lock); | ||
1282 | tda18271_init_regs(fe); | ||
1283 | |||
1284 | if ((tda18271_need_cal_on_startup(cfg)) && | ||
1285 | (priv->id == TDA18271HDC2)) | ||
1286 | tda18271c2_rf_cal_init(fe); | ||
1287 | |||
1288 | mutex_unlock(&priv->lock); | ||
1289 | break; | ||
1290 | default: | ||
1291 | /* existing tuner instance */ | ||
1292 | fe->tuner_priv = priv; | ||
1293 | |||
1294 | /* allow dvb driver to override configuration settings */ | ||
1295 | if (cfg) { | ||
1296 | if (cfg->gate != TDA18271_GATE_ANALOG) | ||
1297 | priv->gate = cfg->gate; | ||
1298 | if (cfg->role) | ||
1299 | priv->role = cfg->role; | ||
1300 | if (cfg->config) | ||
1301 | priv->config = cfg->config; | ||
1302 | if (cfg->small_i2c) | ||
1303 | priv->small_i2c = cfg->small_i2c; | ||
1304 | if (cfg->output_opt) | ||
1305 | priv->output_opt = cfg->output_opt; | ||
1306 | if (cfg->std_map) | ||
1307 | tda18271_update_std_map(fe, cfg->std_map); | ||
1308 | } | ||
1309 | if (tda18271_need_cal_on_startup(cfg)) | ||
1310 | tda18271_init(fe); | ||
1311 | break; | ||
1312 | } | ||
1313 | |||
1314 | /* override default std map with values in config struct */ | ||
1315 | if ((cfg) && (cfg->std_map)) | ||
1316 | tda18271_update_std_map(fe, cfg->std_map); | ||
1317 | |||
1318 | mutex_unlock(&tda18271_list_mutex); | ||
1319 | |||
1320 | memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops, | ||
1321 | sizeof(struct dvb_tuner_ops)); | ||
1322 | |||
1323 | if (tda18271_debug & (DBG_MAP | DBG_ADV)) | ||
1324 | tda18271_dump_std_map(fe); | ||
1325 | |||
1326 | return fe; | ||
1327 | fail: | ||
1328 | mutex_unlock(&tda18271_list_mutex); | ||
1329 | |||
1330 | tda18271_release(fe); | ||
1331 | return NULL; | ||
1332 | } | ||
1333 | EXPORT_SYMBOL_GPL(tda18271_attach); | ||
1334 | MODULE_DESCRIPTION("NXP TDA18271HD analog / digital tuner driver"); | ||
1335 | MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>"); | ||
1336 | MODULE_LICENSE("GPL"); | ||
1337 | MODULE_VERSION("0.4"); | ||
1338 | |||
1339 | /* | ||
1340 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
1341 | * --------------------------------------------------------------------------- | ||
1342 | * Local variables: | ||
1343 | * c-basic-offset: 8 | ||
1344 | * End: | ||
1345 | */ | ||
diff --git a/drivers/media/tuners/tda18271-maps.c b/drivers/media/tuners/tda18271-maps.c new file mode 100644 index 000000000000..fb881c667c94 --- /dev/null +++ b/drivers/media/tuners/tda18271-maps.c | |||
@@ -0,0 +1,1317 @@ | |||
1 | /* | ||
2 | tda18271-maps.c - driver for the Philips / NXP TDA18271 silicon tuner | ||
3 | |||
4 | Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org> | ||
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 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #include "tda18271-priv.h" | ||
22 | |||
23 | struct tda18271_pll_map { | ||
24 | u32 lomax; | ||
25 | u8 pd; /* post div */ | ||
26 | u8 d; /* div */ | ||
27 | }; | ||
28 | |||
29 | struct tda18271_map { | ||
30 | u32 rfmax; | ||
31 | u8 val; | ||
32 | }; | ||
33 | |||
34 | /*---------------------------------------------------------------------*/ | ||
35 | |||
36 | static struct tda18271_pll_map tda18271c1_main_pll[] = { | ||
37 | { .lomax = 32000, .pd = 0x5f, .d = 0xf0 }, | ||
38 | { .lomax = 35000, .pd = 0x5e, .d = 0xe0 }, | ||
39 | { .lomax = 37000, .pd = 0x5d, .d = 0xd0 }, | ||
40 | { .lomax = 41000, .pd = 0x5c, .d = 0xc0 }, | ||
41 | { .lomax = 44000, .pd = 0x5b, .d = 0xb0 }, | ||
42 | { .lomax = 49000, .pd = 0x5a, .d = 0xa0 }, | ||
43 | { .lomax = 54000, .pd = 0x59, .d = 0x90 }, | ||
44 | { .lomax = 61000, .pd = 0x58, .d = 0x80 }, | ||
45 | { .lomax = 65000, .pd = 0x4f, .d = 0x78 }, | ||
46 | { .lomax = 70000, .pd = 0x4e, .d = 0x70 }, | ||
47 | { .lomax = 75000, .pd = 0x4d, .d = 0x68 }, | ||
48 | { .lomax = 82000, .pd = 0x4c, .d = 0x60 }, | ||
49 | { .lomax = 89000, .pd = 0x4b, .d = 0x58 }, | ||
50 | { .lomax = 98000, .pd = 0x4a, .d = 0x50 }, | ||
51 | { .lomax = 109000, .pd = 0x49, .d = 0x48 }, | ||
52 | { .lomax = 123000, .pd = 0x48, .d = 0x40 }, | ||
53 | { .lomax = 131000, .pd = 0x3f, .d = 0x3c }, | ||
54 | { .lomax = 141000, .pd = 0x3e, .d = 0x38 }, | ||
55 | { .lomax = 151000, .pd = 0x3d, .d = 0x34 }, | ||
56 | { .lomax = 164000, .pd = 0x3c, .d = 0x30 }, | ||
57 | { .lomax = 179000, .pd = 0x3b, .d = 0x2c }, | ||
58 | { .lomax = 197000, .pd = 0x3a, .d = 0x28 }, | ||
59 | { .lomax = 219000, .pd = 0x39, .d = 0x24 }, | ||
60 | { .lomax = 246000, .pd = 0x38, .d = 0x20 }, | ||
61 | { .lomax = 263000, .pd = 0x2f, .d = 0x1e }, | ||
62 | { .lomax = 282000, .pd = 0x2e, .d = 0x1c }, | ||
63 | { .lomax = 303000, .pd = 0x2d, .d = 0x1a }, | ||
64 | { .lomax = 329000, .pd = 0x2c, .d = 0x18 }, | ||
65 | { .lomax = 359000, .pd = 0x2b, .d = 0x16 }, | ||
66 | { .lomax = 395000, .pd = 0x2a, .d = 0x14 }, | ||
67 | { .lomax = 438000, .pd = 0x29, .d = 0x12 }, | ||
68 | { .lomax = 493000, .pd = 0x28, .d = 0x10 }, | ||
69 | { .lomax = 526000, .pd = 0x1f, .d = 0x0f }, | ||
70 | { .lomax = 564000, .pd = 0x1e, .d = 0x0e }, | ||
71 | { .lomax = 607000, .pd = 0x1d, .d = 0x0d }, | ||
72 | { .lomax = 658000, .pd = 0x1c, .d = 0x0c }, | ||
73 | { .lomax = 718000, .pd = 0x1b, .d = 0x0b }, | ||
74 | { .lomax = 790000, .pd = 0x1a, .d = 0x0a }, | ||
75 | { .lomax = 877000, .pd = 0x19, .d = 0x09 }, | ||
76 | { .lomax = 987000, .pd = 0x18, .d = 0x08 }, | ||
77 | { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ | ||
78 | }; | ||
79 | |||
80 | static struct tda18271_pll_map tda18271c2_main_pll[] = { | ||
81 | { .lomax = 33125, .pd = 0x57, .d = 0xf0 }, | ||
82 | { .lomax = 35500, .pd = 0x56, .d = 0xe0 }, | ||
83 | { .lomax = 38188, .pd = 0x55, .d = 0xd0 }, | ||
84 | { .lomax = 41375, .pd = 0x54, .d = 0xc0 }, | ||
85 | { .lomax = 45125, .pd = 0x53, .d = 0xb0 }, | ||
86 | { .lomax = 49688, .pd = 0x52, .d = 0xa0 }, | ||
87 | { .lomax = 55188, .pd = 0x51, .d = 0x90 }, | ||
88 | { .lomax = 62125, .pd = 0x50, .d = 0x80 }, | ||
89 | { .lomax = 66250, .pd = 0x47, .d = 0x78 }, | ||
90 | { .lomax = 71000, .pd = 0x46, .d = 0x70 }, | ||
91 | { .lomax = 76375, .pd = 0x45, .d = 0x68 }, | ||
92 | { .lomax = 82750, .pd = 0x44, .d = 0x60 }, | ||
93 | { .lomax = 90250, .pd = 0x43, .d = 0x58 }, | ||
94 | { .lomax = 99375, .pd = 0x42, .d = 0x50 }, | ||
95 | { .lomax = 110375, .pd = 0x41, .d = 0x48 }, | ||
96 | { .lomax = 124250, .pd = 0x40, .d = 0x40 }, | ||
97 | { .lomax = 132500, .pd = 0x37, .d = 0x3c }, | ||
98 | { .lomax = 142000, .pd = 0x36, .d = 0x38 }, | ||
99 | { .lomax = 152750, .pd = 0x35, .d = 0x34 }, | ||
100 | { .lomax = 165500, .pd = 0x34, .d = 0x30 }, | ||
101 | { .lomax = 180500, .pd = 0x33, .d = 0x2c }, | ||
102 | { .lomax = 198750, .pd = 0x32, .d = 0x28 }, | ||
103 | { .lomax = 220750, .pd = 0x31, .d = 0x24 }, | ||
104 | { .lomax = 248500, .pd = 0x30, .d = 0x20 }, | ||
105 | { .lomax = 265000, .pd = 0x27, .d = 0x1e }, | ||
106 | { .lomax = 284000, .pd = 0x26, .d = 0x1c }, | ||
107 | { .lomax = 305500, .pd = 0x25, .d = 0x1a }, | ||
108 | { .lomax = 331000, .pd = 0x24, .d = 0x18 }, | ||
109 | { .lomax = 361000, .pd = 0x23, .d = 0x16 }, | ||
110 | { .lomax = 397500, .pd = 0x22, .d = 0x14 }, | ||
111 | { .lomax = 441500, .pd = 0x21, .d = 0x12 }, | ||
112 | { .lomax = 497000, .pd = 0x20, .d = 0x10 }, | ||
113 | { .lomax = 530000, .pd = 0x17, .d = 0x0f }, | ||
114 | { .lomax = 568000, .pd = 0x16, .d = 0x0e }, | ||
115 | { .lomax = 611000, .pd = 0x15, .d = 0x0d }, | ||
116 | { .lomax = 662000, .pd = 0x14, .d = 0x0c }, | ||
117 | { .lomax = 722000, .pd = 0x13, .d = 0x0b }, | ||
118 | { .lomax = 795000, .pd = 0x12, .d = 0x0a }, | ||
119 | { .lomax = 883000, .pd = 0x11, .d = 0x09 }, | ||
120 | { .lomax = 994000, .pd = 0x10, .d = 0x08 }, | ||
121 | { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ | ||
122 | }; | ||
123 | |||
124 | static struct tda18271_pll_map tda18271c1_cal_pll[] = { | ||
125 | { .lomax = 33000, .pd = 0xdd, .d = 0xd0 }, | ||
126 | { .lomax = 36000, .pd = 0xdc, .d = 0xc0 }, | ||
127 | { .lomax = 40000, .pd = 0xdb, .d = 0xb0 }, | ||
128 | { .lomax = 44000, .pd = 0xda, .d = 0xa0 }, | ||
129 | { .lomax = 49000, .pd = 0xd9, .d = 0x90 }, | ||
130 | { .lomax = 55000, .pd = 0xd8, .d = 0x80 }, | ||
131 | { .lomax = 63000, .pd = 0xd3, .d = 0x70 }, | ||
132 | { .lomax = 67000, .pd = 0xcd, .d = 0x68 }, | ||
133 | { .lomax = 73000, .pd = 0xcc, .d = 0x60 }, | ||
134 | { .lomax = 80000, .pd = 0xcb, .d = 0x58 }, | ||
135 | { .lomax = 88000, .pd = 0xca, .d = 0x50 }, | ||
136 | { .lomax = 98000, .pd = 0xc9, .d = 0x48 }, | ||
137 | { .lomax = 110000, .pd = 0xc8, .d = 0x40 }, | ||
138 | { .lomax = 126000, .pd = 0xc3, .d = 0x38 }, | ||
139 | { .lomax = 135000, .pd = 0xbd, .d = 0x34 }, | ||
140 | { .lomax = 147000, .pd = 0xbc, .d = 0x30 }, | ||
141 | { .lomax = 160000, .pd = 0xbb, .d = 0x2c }, | ||
142 | { .lomax = 176000, .pd = 0xba, .d = 0x28 }, | ||
143 | { .lomax = 196000, .pd = 0xb9, .d = 0x24 }, | ||
144 | { .lomax = 220000, .pd = 0xb8, .d = 0x20 }, | ||
145 | { .lomax = 252000, .pd = 0xb3, .d = 0x1c }, | ||
146 | { .lomax = 271000, .pd = 0xad, .d = 0x1a }, | ||
147 | { .lomax = 294000, .pd = 0xac, .d = 0x18 }, | ||
148 | { .lomax = 321000, .pd = 0xab, .d = 0x16 }, | ||
149 | { .lomax = 353000, .pd = 0xaa, .d = 0x14 }, | ||
150 | { .lomax = 392000, .pd = 0xa9, .d = 0x12 }, | ||
151 | { .lomax = 441000, .pd = 0xa8, .d = 0x10 }, | ||
152 | { .lomax = 505000, .pd = 0xa3, .d = 0x0e }, | ||
153 | { .lomax = 543000, .pd = 0x9d, .d = 0x0d }, | ||
154 | { .lomax = 589000, .pd = 0x9c, .d = 0x0c }, | ||
155 | { .lomax = 642000, .pd = 0x9b, .d = 0x0b }, | ||
156 | { .lomax = 707000, .pd = 0x9a, .d = 0x0a }, | ||
157 | { .lomax = 785000, .pd = 0x99, .d = 0x09 }, | ||
158 | { .lomax = 883000, .pd = 0x98, .d = 0x08 }, | ||
159 | { .lomax = 1010000, .pd = 0x93, .d = 0x07 }, | ||
160 | { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ | ||
161 | }; | ||
162 | |||
163 | static struct tda18271_pll_map tda18271c2_cal_pll[] = { | ||
164 | { .lomax = 33813, .pd = 0xdd, .d = 0xd0 }, | ||
165 | { .lomax = 36625, .pd = 0xdc, .d = 0xc0 }, | ||
166 | { .lomax = 39938, .pd = 0xdb, .d = 0xb0 }, | ||
167 | { .lomax = 43938, .pd = 0xda, .d = 0xa0 }, | ||
168 | { .lomax = 48813, .pd = 0xd9, .d = 0x90 }, | ||
169 | { .lomax = 54938, .pd = 0xd8, .d = 0x80 }, | ||
170 | { .lomax = 62813, .pd = 0xd3, .d = 0x70 }, | ||
171 | { .lomax = 67625, .pd = 0xcd, .d = 0x68 }, | ||
172 | { .lomax = 73250, .pd = 0xcc, .d = 0x60 }, | ||
173 | { .lomax = 79875, .pd = 0xcb, .d = 0x58 }, | ||
174 | { .lomax = 87875, .pd = 0xca, .d = 0x50 }, | ||
175 | { .lomax = 97625, .pd = 0xc9, .d = 0x48 }, | ||
176 | { .lomax = 109875, .pd = 0xc8, .d = 0x40 }, | ||
177 | { .lomax = 125625, .pd = 0xc3, .d = 0x38 }, | ||
178 | { .lomax = 135250, .pd = 0xbd, .d = 0x34 }, | ||
179 | { .lomax = 146500, .pd = 0xbc, .d = 0x30 }, | ||
180 | { .lomax = 159750, .pd = 0xbb, .d = 0x2c }, | ||
181 | { .lomax = 175750, .pd = 0xba, .d = 0x28 }, | ||
182 | { .lomax = 195250, .pd = 0xb9, .d = 0x24 }, | ||
183 | { .lomax = 219750, .pd = 0xb8, .d = 0x20 }, | ||
184 | { .lomax = 251250, .pd = 0xb3, .d = 0x1c }, | ||
185 | { .lomax = 270500, .pd = 0xad, .d = 0x1a }, | ||
186 | { .lomax = 293000, .pd = 0xac, .d = 0x18 }, | ||
187 | { .lomax = 319500, .pd = 0xab, .d = 0x16 }, | ||
188 | { .lomax = 351500, .pd = 0xaa, .d = 0x14 }, | ||
189 | { .lomax = 390500, .pd = 0xa9, .d = 0x12 }, | ||
190 | { .lomax = 439500, .pd = 0xa8, .d = 0x10 }, | ||
191 | { .lomax = 502500, .pd = 0xa3, .d = 0x0e }, | ||
192 | { .lomax = 541000, .pd = 0x9d, .d = 0x0d }, | ||
193 | { .lomax = 586000, .pd = 0x9c, .d = 0x0c }, | ||
194 | { .lomax = 639000, .pd = 0x9b, .d = 0x0b }, | ||
195 | { .lomax = 703000, .pd = 0x9a, .d = 0x0a }, | ||
196 | { .lomax = 781000, .pd = 0x99, .d = 0x09 }, | ||
197 | { .lomax = 879000, .pd = 0x98, .d = 0x08 }, | ||
198 | { .lomax = 0, .pd = 0x00, .d = 0x00 }, /* end */ | ||
199 | }; | ||
200 | |||
201 | static struct tda18271_map tda18271_bp_filter[] = { | ||
202 | { .rfmax = 62000, .val = 0x00 }, | ||
203 | { .rfmax = 84000, .val = 0x01 }, | ||
204 | { .rfmax = 100000, .val = 0x02 }, | ||
205 | { .rfmax = 140000, .val = 0x03 }, | ||
206 | { .rfmax = 170000, .val = 0x04 }, | ||
207 | { .rfmax = 180000, .val = 0x05 }, | ||
208 | { .rfmax = 865000, .val = 0x06 }, | ||
209 | { .rfmax = 0, .val = 0x00 }, /* end */ | ||
210 | }; | ||
211 | |||
212 | static struct tda18271_map tda18271c1_km[] = { | ||
213 | { .rfmax = 61100, .val = 0x74 }, | ||
214 | { .rfmax = 350000, .val = 0x40 }, | ||
215 | { .rfmax = 720000, .val = 0x30 }, | ||
216 | { .rfmax = 865000, .val = 0x40 }, | ||
217 | { .rfmax = 0, .val = 0x00 }, /* end */ | ||
218 | }; | ||
219 | |||
220 | static struct tda18271_map tda18271c2_km[] = { | ||
221 | { .rfmax = 47900, .val = 0x38 }, | ||
222 | { .rfmax = 61100, .val = 0x44 }, | ||
223 | { .rfmax = 350000, .val = 0x30 }, | ||
224 | { .rfmax = 720000, .val = 0x24 }, | ||
225 | { .rfmax = 865000, .val = 0x3c }, | ||
226 | { .rfmax = 0, .val = 0x00 }, /* end */ | ||
227 | }; | ||
228 | |||
229 | static struct tda18271_map tda18271_rf_band[] = { | ||
230 | { .rfmax = 47900, .val = 0x00 }, | ||
231 | { .rfmax = 61100, .val = 0x01 }, | ||
232 | { .rfmax = 152600, .val = 0x02 }, | ||
233 | { .rfmax = 164700, .val = 0x03 }, | ||
234 | { .rfmax = 203500, .val = 0x04 }, | ||
235 | { .rfmax = 457800, .val = 0x05 }, | ||
236 | { .rfmax = 865000, .val = 0x06 }, | ||
237 | { .rfmax = 0, .val = 0x00 }, /* end */ | ||
238 | }; | ||
239 | |||
240 | static struct tda18271_map tda18271_gain_taper[] = { | ||
241 | { .rfmax = 45400, .val = 0x1f }, | ||
242 | { .rfmax = 45800, .val = 0x1e }, | ||
243 | { .rfmax = 46200, .val = 0x1d }, | ||
244 | { .rfmax = 46700, .val = 0x1c }, | ||
245 | { .rfmax = 47100, .val = 0x1b }, | ||
246 | { .rfmax = 47500, .val = 0x1a }, | ||
247 | { .rfmax = 47900, .val = 0x19 }, | ||
248 | { .rfmax = 49600, .val = 0x17 }, | ||
249 | { .rfmax = 51200, .val = 0x16 }, | ||
250 | { .rfmax = 52900, .val = 0x15 }, | ||
251 | { .rfmax = 54500, .val = 0x14 }, | ||
252 | { .rfmax = 56200, .val = 0x13 }, | ||
253 | { .rfmax = 57800, .val = 0x12 }, | ||
254 | { .rfmax = 59500, .val = 0x11 }, | ||
255 | { .rfmax = 61100, .val = 0x10 }, | ||
256 | { .rfmax = 67600, .val = 0x0d }, | ||
257 | { .rfmax = 74200, .val = 0x0c }, | ||
258 | { .rfmax = 80700, .val = 0x0b }, | ||
259 | { .rfmax = 87200, .val = 0x0a }, | ||
260 | { .rfmax = 93800, .val = 0x09 }, | ||
261 | { .rfmax = 100300, .val = 0x08 }, | ||
262 | { .rfmax = 106900, .val = 0x07 }, | ||
263 | { .rfmax = 113400, .val = 0x06 }, | ||
264 | { .rfmax = 119900, .val = 0x05 }, | ||
265 | { .rfmax = 126500, .val = 0x04 }, | ||
266 | { .rfmax = 133000, .val = 0x03 }, | ||
267 | { .rfmax = 139500, .val = 0x02 }, | ||
268 | { .rfmax = 146100, .val = 0x01 }, | ||
269 | { .rfmax = 152600, .val = 0x00 }, | ||
270 | { .rfmax = 154300, .val = 0x1f }, | ||
271 | { .rfmax = 156100, .val = 0x1e }, | ||
272 | { .rfmax = 157800, .val = 0x1d }, | ||
273 | { .rfmax = 159500, .val = 0x1c }, | ||
274 | { .rfmax = 161200, .val = 0x1b }, | ||
275 | { .rfmax = 163000, .val = 0x1a }, | ||
276 | { .rfmax = 164700, .val = 0x19 }, | ||
277 | { .rfmax = 170200, .val = 0x17 }, | ||
278 | { .rfmax = 175800, .val = 0x16 }, | ||
279 | { .rfmax = 181300, .val = 0x15 }, | ||
280 | { .rfmax = 186900, .val = 0x14 }, | ||
281 | { .rfmax = 192400, .val = 0x13 }, | ||
282 | { .rfmax = 198000, .val = 0x12 }, | ||
283 | { .rfmax = 203500, .val = 0x11 }, | ||
284 | { .rfmax = 216200, .val = 0x14 }, | ||
285 | { .rfmax = 228900, .val = 0x13 }, | ||
286 | { .rfmax = 241600, .val = 0x12 }, | ||
287 | { .rfmax = 254400, .val = 0x11 }, | ||
288 | { .rfmax = 267100, .val = 0x10 }, | ||
289 | { .rfmax = 279800, .val = 0x0f }, | ||
290 | { .rfmax = 292500, .val = 0x0e }, | ||
291 | { .rfmax = 305200, .val = 0x0d }, | ||
292 | { .rfmax = 317900, .val = 0x0c }, | ||
293 | { .rfmax = 330700, .val = 0x0b }, | ||
294 | { .rfmax = 343400, .val = 0x0a }, | ||
295 | { .rfmax = 356100, .val = 0x09 }, | ||
296 | { .rfmax = 368800, .val = 0x08 }, | ||
297 | { .rfmax = 381500, .val = 0x07 }, | ||
298 | { .rfmax = 394200, .val = 0x06 }, | ||
299 | { .rfmax = 406900, .val = 0x05 }, | ||
300 | { .rfmax = 419700, .val = 0x04 }, | ||
301 | { .rfmax = 432400, .val = 0x03 }, | ||
302 | { .rfmax = 445100, .val = 0x02 }, | ||
303 | { .rfmax = 457800, .val = 0x01 }, | ||
304 | { .rfmax = 476300, .val = 0x19 }, | ||
305 | { .rfmax = 494800, .val = 0x18 }, | ||
306 | { .rfmax = 513300, .val = 0x17 }, | ||
307 | { .rfmax = 531800, .val = 0x16 }, | ||
308 | { .rfmax = 550300, .val = 0x15 }, | ||
309 | { .rfmax = 568900, .val = 0x14 }, | ||
310 | { .rfmax = 587400, .val = 0x13 }, | ||
311 | { .rfmax = 605900, .val = 0x12 }, | ||
312 | { .rfmax = 624400, .val = 0x11 }, | ||
313 | { .rfmax = 642900, .val = 0x10 }, | ||
314 | { .rfmax = 661400, .val = 0x0f }, | ||
315 | { .rfmax = 679900, .val = 0x0e }, | ||
316 | { .rfmax = 698400, .val = 0x0d }, | ||
317 | { .rfmax = 716900, .val = 0x0c }, | ||
318 | { .rfmax = 735400, .val = 0x0b }, | ||
319 | { .rfmax = 753900, .val = 0x0a }, | ||
320 | { .rfmax = 772500, .val = 0x09 }, | ||
321 | { .rfmax = 791000, .val = 0x08 }, | ||
322 | { .rfmax = 809500, .val = 0x07 }, | ||
323 | { .rfmax = 828000, .val = 0x06 }, | ||
324 | { .rfmax = 846500, .val = 0x05 }, | ||
325 | { .rfmax = 865000, .val = 0x04 }, | ||
326 | { .rfmax = 0, .val = 0x00 }, /* end */ | ||
327 | }; | ||
328 | |||
329 | static struct tda18271_map tda18271c1_rf_cal[] = { | ||
330 | { .rfmax = 41000, .val = 0x1e }, | ||
331 | { .rfmax = 43000, .val = 0x30 }, | ||
332 | { .rfmax = 45000, .val = 0x43 }, | ||
333 | { .rfmax = 46000, .val = 0x4d }, | ||
334 | { .rfmax = 47000, .val = 0x54 }, | ||
335 | { .rfmax = 47900, .val = 0x64 }, | ||
336 | { .rfmax = 49100, .val = 0x20 }, | ||
337 | { .rfmax = 50000, .val = 0x22 }, | ||
338 | { .rfmax = 51000, .val = 0x2a }, | ||
339 | { .rfmax = 53000, .val = 0x32 }, | ||
340 | { .rfmax = 55000, .val = 0x35 }, | ||
341 | { .rfmax = 56000, .val = 0x3c }, | ||
342 | { .rfmax = 57000, .val = 0x3f }, | ||
343 | { .rfmax = 58000, .val = 0x48 }, | ||
344 | { .rfmax = 59000, .val = 0x4d }, | ||
345 | { .rfmax = 60000, .val = 0x58 }, | ||
346 | { .rfmax = 61100, .val = 0x5f }, | ||
347 | { .rfmax = 0, .val = 0x00 }, /* end */ | ||
348 | }; | ||
349 | |||
350 | static struct tda18271_map tda18271c2_rf_cal[] = { | ||
351 | { .rfmax = 41000, .val = 0x0f }, | ||
352 | { .rfmax = 43000, .val = 0x1c }, | ||
353 | { .rfmax = 45000, .val = 0x2f }, | ||
354 | { .rfmax = 46000, .val = 0x39 }, | ||
355 | { .rfmax = 47000, .val = 0x40 }, | ||
356 | { .rfmax = 47900, .val = 0x50 }, | ||
357 | { .rfmax = 49100, .val = 0x16 }, | ||
358 | { .rfmax = 50000, .val = 0x18 }, | ||
359 | { .rfmax = 51000, .val = 0x20 }, | ||
360 | { .rfmax = 53000, .val = 0x28 }, | ||
361 | { .rfmax = 55000, .val = 0x2b }, | ||
362 | { .rfmax = 56000, .val = 0x32 }, | ||
363 | { .rfmax = 57000, .val = 0x35 }, | ||
364 | { .rfmax = 58000, .val = 0x3e }, | ||
365 | { .rfmax = 59000, .val = 0x43 }, | ||
366 | { .rfmax = 60000, .val = 0x4e }, | ||
367 | { .rfmax = 61100, .val = 0x55 }, | ||
368 | { .rfmax = 63000, .val = 0x0f }, | ||
369 | { .rfmax = 64000, .val = 0x11 }, | ||
370 | { .rfmax = 65000, .val = 0x12 }, | ||
371 | { .rfmax = 66000, .val = 0x15 }, | ||
372 | { .rfmax = 67000, .val = 0x16 }, | ||
373 | { .rfmax = 68000, .val = 0x17 }, | ||
374 | { .rfmax = 70000, .val = 0x19 }, | ||
375 | { .rfmax = 71000, .val = 0x1c }, | ||
376 | { .rfmax = 72000, .val = 0x1d }, | ||
377 | { .rfmax = 73000, .val = 0x1f }, | ||
378 | { .rfmax = 74000, .val = 0x20 }, | ||
379 | { .rfmax = 75000, .val = 0x21 }, | ||
380 | { .rfmax = 76000, .val = 0x24 }, | ||
381 | { .rfmax = 77000, .val = 0x25 }, | ||
382 | { .rfmax = 78000, .val = 0x27 }, | ||
383 | { .rfmax = 80000, .val = 0x28 }, | ||
384 | { .rfmax = 81000, .val = 0x29 }, | ||
385 | { .rfmax = 82000, .val = 0x2d }, | ||
386 | { .rfmax = 83000, .val = 0x2e }, | ||
387 | { .rfmax = 84000, .val = 0x2f }, | ||
388 | { .rfmax = 85000, .val = 0x31 }, | ||
389 | { .rfmax = 86000, .val = 0x33 }, | ||
390 | { .rfmax = 87000, .val = 0x34 }, | ||
391 | { .rfmax = 88000, .val = 0x35 }, | ||
392 | { .rfmax = 89000, .val = 0x37 }, | ||
393 | { .rfmax = 90000, .val = 0x38 }, | ||
394 | { .rfmax = 91000, .val = 0x39 }, | ||
395 | { .rfmax = 93000, .val = 0x3c }, | ||
396 | { .rfmax = 94000, .val = 0x3e }, | ||
397 | { .rfmax = 95000, .val = 0x3f }, | ||
398 | { .rfmax = 96000, .val = 0x40 }, | ||
399 | { .rfmax = 97000, .val = 0x42 }, | ||
400 | { .rfmax = 99000, .val = 0x45 }, | ||
401 | { .rfmax = 100000, .val = 0x46 }, | ||
402 | { .rfmax = 102000, .val = 0x48 }, | ||
403 | { .rfmax = 103000, .val = 0x4a }, | ||
404 | { .rfmax = 105000, .val = 0x4d }, | ||
405 | { .rfmax = 106000, .val = 0x4e }, | ||
406 | { .rfmax = 107000, .val = 0x50 }, | ||
407 | { .rfmax = 108000, .val = 0x51 }, | ||
408 | { .rfmax = 110000, .val = 0x54 }, | ||
409 | { .rfmax = 111000, .val = 0x56 }, | ||
410 | { .rfmax = 112000, .val = 0x57 }, | ||
411 | { .rfmax = 113000, .val = 0x58 }, | ||
412 | { .rfmax = 114000, .val = 0x59 }, | ||
413 | { .rfmax = 115000, .val = 0x5c }, | ||
414 | { .rfmax = 116000, .val = 0x5d }, | ||
415 | { .rfmax = 117000, .val = 0x5f }, | ||
416 | { .rfmax = 119000, .val = 0x60 }, | ||
417 | { .rfmax = 120000, .val = 0x64 }, | ||
418 | { .rfmax = 121000, .val = 0x65 }, | ||
419 | { .rfmax = 122000, .val = 0x66 }, | ||
420 | { .rfmax = 123000, .val = 0x68 }, | ||
421 | { .rfmax = 124000, .val = 0x69 }, | ||
422 | { .rfmax = 125000, .val = 0x6c }, | ||
423 | { .rfmax = 126000, .val = 0x6d }, | ||
424 | { .rfmax = 127000, .val = 0x6e }, | ||
425 | { .rfmax = 128000, .val = 0x70 }, | ||
426 | { .rfmax = 129000, .val = 0x71 }, | ||
427 | { .rfmax = 130000, .val = 0x75 }, | ||
428 | { .rfmax = 131000, .val = 0x77 }, | ||
429 | { .rfmax = 132000, .val = 0x78 }, | ||
430 | { .rfmax = 133000, .val = 0x7b }, | ||
431 | { .rfmax = 134000, .val = 0x7e }, | ||
432 | { .rfmax = 135000, .val = 0x81 }, | ||
433 | { .rfmax = 136000, .val = 0x82 }, | ||
434 | { .rfmax = 137000, .val = 0x87 }, | ||
435 | { .rfmax = 138000, .val = 0x88 }, | ||
436 | { .rfmax = 139000, .val = 0x8d }, | ||
437 | { .rfmax = 140000, .val = 0x8e }, | ||
438 | { .rfmax = 141000, .val = 0x91 }, | ||
439 | { .rfmax = 142000, .val = 0x95 }, | ||
440 | { .rfmax = 143000, .val = 0x9a }, | ||
441 | { .rfmax = 144000, .val = 0x9d }, | ||
442 | { .rfmax = 145000, .val = 0xa1 }, | ||
443 | { .rfmax = 146000, .val = 0xa2 }, | ||
444 | { .rfmax = 147000, .val = 0xa4 }, | ||
445 | { .rfmax = 148000, .val = 0xa9 }, | ||
446 | { .rfmax = 149000, .val = 0xae }, | ||
447 | { .rfmax = 150000, .val = 0xb0 }, | ||
448 | { .rfmax = 151000, .val = 0xb1 }, | ||
449 | { .rfmax = 152000, .val = 0xb7 }, | ||
450 | { .rfmax = 152600, .val = 0xbd }, | ||
451 | { .rfmax = 154000, .val = 0x20 }, | ||
452 | { .rfmax = 155000, .val = 0x22 }, | ||
453 | { .rfmax = 156000, .val = 0x24 }, | ||
454 | { .rfmax = 157000, .val = 0x25 }, | ||
455 | { .rfmax = 158000, .val = 0x27 }, | ||
456 | { .rfmax = 159000, .val = 0x29 }, | ||
457 | { .rfmax = 160000, .val = 0x2c }, | ||
458 | { .rfmax = 161000, .val = 0x2d }, | ||
459 | { .rfmax = 163000, .val = 0x2e }, | ||
460 | { .rfmax = 164000, .val = 0x2f }, | ||
461 | { .rfmax = 164700, .val = 0x30 }, | ||
462 | { .rfmax = 166000, .val = 0x11 }, | ||
463 | { .rfmax = 167000, .val = 0x12 }, | ||
464 | { .rfmax = 168000, .val = 0x13 }, | ||
465 | { .rfmax = 169000, .val = 0x14 }, | ||
466 | { .rfmax = 170000, .val = 0x15 }, | ||
467 | { .rfmax = 172000, .val = 0x16 }, | ||
468 | { .rfmax = 173000, .val = 0x17 }, | ||
469 | { .rfmax = 174000, .val = 0x18 }, | ||
470 | { .rfmax = 175000, .val = 0x1a }, | ||
471 | { .rfmax = 176000, .val = 0x1b }, | ||
472 | { .rfmax = 178000, .val = 0x1d }, | ||
473 | { .rfmax = 179000, .val = 0x1e }, | ||
474 | { .rfmax = 180000, .val = 0x1f }, | ||
475 | { .rfmax = 181000, .val = 0x20 }, | ||
476 | { .rfmax = 182000, .val = 0x21 }, | ||
477 | { .rfmax = 183000, .val = 0x22 }, | ||
478 | { .rfmax = 184000, .val = 0x24 }, | ||
479 | { .rfmax = 185000, .val = 0x25 }, | ||
480 | { .rfmax = 186000, .val = 0x26 }, | ||
481 | { .rfmax = 187000, .val = 0x27 }, | ||
482 | { .rfmax = 188000, .val = 0x29 }, | ||
483 | { .rfmax = 189000, .val = 0x2a }, | ||
484 | { .rfmax = 190000, .val = 0x2c }, | ||
485 | { .rfmax = 191000, .val = 0x2d }, | ||
486 | { .rfmax = 192000, .val = 0x2e }, | ||
487 | { .rfmax = 193000, .val = 0x2f }, | ||
488 | { .rfmax = 194000, .val = 0x30 }, | ||
489 | { .rfmax = 195000, .val = 0x33 }, | ||
490 | { .rfmax = 196000, .val = 0x35 }, | ||
491 | { .rfmax = 198000, .val = 0x36 }, | ||
492 | { .rfmax = 200000, .val = 0x38 }, | ||
493 | { .rfmax = 201000, .val = 0x3c }, | ||
494 | { .rfmax = 202000, .val = 0x3d }, | ||
495 | { .rfmax = 203500, .val = 0x3e }, | ||
496 | { .rfmax = 206000, .val = 0x0e }, | ||
497 | { .rfmax = 208000, .val = 0x0f }, | ||
498 | { .rfmax = 212000, .val = 0x10 }, | ||
499 | { .rfmax = 216000, .val = 0x11 }, | ||
500 | { .rfmax = 217000, .val = 0x12 }, | ||
501 | { .rfmax = 218000, .val = 0x13 }, | ||
502 | { .rfmax = 220000, .val = 0x14 }, | ||
503 | { .rfmax = 222000, .val = 0x15 }, | ||
504 | { .rfmax = 225000, .val = 0x16 }, | ||
505 | { .rfmax = 228000, .val = 0x17 }, | ||
506 | { .rfmax = 231000, .val = 0x18 }, | ||
507 | { .rfmax = 234000, .val = 0x19 }, | ||
508 | { .rfmax = 235000, .val = 0x1a }, | ||
509 | { .rfmax = 236000, .val = 0x1b }, | ||
510 | { .rfmax = 237000, .val = 0x1c }, | ||
511 | { .rfmax = 240000, .val = 0x1d }, | ||
512 | { .rfmax = 242000, .val = 0x1e }, | ||
513 | { .rfmax = 244000, .val = 0x1f }, | ||
514 | { .rfmax = 247000, .val = 0x20 }, | ||
515 | { .rfmax = 249000, .val = 0x21 }, | ||
516 | { .rfmax = 252000, .val = 0x22 }, | ||
517 | { .rfmax = 253000, .val = 0x23 }, | ||
518 | { .rfmax = 254000, .val = 0x24 }, | ||
519 | { .rfmax = 256000, .val = 0x25 }, | ||
520 | { .rfmax = 259000, .val = 0x26 }, | ||
521 | { .rfmax = 262000, .val = 0x27 }, | ||
522 | { .rfmax = 264000, .val = 0x28 }, | ||
523 | { .rfmax = 267000, .val = 0x29 }, | ||
524 | { .rfmax = 269000, .val = 0x2a }, | ||
525 | { .rfmax = 271000, .val = 0x2b }, | ||
526 | { .rfmax = 273000, .val = 0x2c }, | ||
527 | { .rfmax = 275000, .val = 0x2d }, | ||
528 | { .rfmax = 277000, .val = 0x2e }, | ||
529 | { .rfmax = 279000, .val = 0x2f }, | ||
530 | { .rfmax = 282000, .val = 0x30 }, | ||
531 | { .rfmax = 284000, .val = 0x31 }, | ||
532 | { .rfmax = 286000, .val = 0x32 }, | ||
533 | { .rfmax = 287000, .val = 0x33 }, | ||
534 | { .rfmax = 290000, .val = 0x34 }, | ||
535 | { .rfmax = 293000, .val = 0x35 }, | ||
536 | { .rfmax = 295000, .val = 0x36 }, | ||
537 | { .rfmax = 297000, .val = 0x37 }, | ||
538 | { .rfmax = 300000, .val = 0x38 }, | ||
539 | { .rfmax = 303000, .val = 0x39 }, | ||
540 | { .rfmax = 305000, .val = 0x3a }, | ||
541 | { .rfmax = 306000, .val = 0x3b }, | ||
542 | { .rfmax = 307000, .val = 0x3c }, | ||
543 | { .rfmax = 310000, .val = 0x3d }, | ||
544 | { .rfmax = 312000, .val = 0x3e }, | ||
545 | { .rfmax = 315000, .val = 0x3f }, | ||
546 | { .rfmax = 318000, .val = 0x40 }, | ||
547 | { .rfmax = 320000, .val = 0x41 }, | ||
548 | { .rfmax = 323000, .val = 0x42 }, | ||
549 | { .rfmax = 324000, .val = 0x43 }, | ||
550 | { .rfmax = 325000, .val = 0x44 }, | ||
551 | { .rfmax = 327000, .val = 0x45 }, | ||
552 | { .rfmax = 331000, .val = 0x46 }, | ||
553 | { .rfmax = 334000, .val = 0x47 }, | ||
554 | { .rfmax = 337000, .val = 0x48 }, | ||
555 | { .rfmax = 339000, .val = 0x49 }, | ||
556 | { .rfmax = 340000, .val = 0x4a }, | ||
557 | { .rfmax = 341000, .val = 0x4b }, | ||
558 | { .rfmax = 343000, .val = 0x4c }, | ||
559 | { .rfmax = 345000, .val = 0x4d }, | ||
560 | { .rfmax = 349000, .val = 0x4e }, | ||
561 | { .rfmax = 352000, .val = 0x4f }, | ||
562 | { .rfmax = 353000, .val = 0x50 }, | ||
563 | { .rfmax = 355000, .val = 0x51 }, | ||
564 | { .rfmax = 357000, .val = 0x52 }, | ||
565 | { .rfmax = 359000, .val = 0x53 }, | ||
566 | { .rfmax = 361000, .val = 0x54 }, | ||
567 | { .rfmax = 362000, .val = 0x55 }, | ||
568 | { .rfmax = 364000, .val = 0x56 }, | ||
569 | { .rfmax = 368000, .val = 0x57 }, | ||
570 | { .rfmax = 370000, .val = 0x58 }, | ||
571 | { .rfmax = 372000, .val = 0x59 }, | ||
572 | { .rfmax = 375000, .val = 0x5a }, | ||
573 | { .rfmax = 376000, .val = 0x5b }, | ||
574 | { .rfmax = 377000, .val = 0x5c }, | ||
575 | { .rfmax = 379000, .val = 0x5d }, | ||
576 | { .rfmax = 382000, .val = 0x5e }, | ||
577 | { .rfmax = 384000, .val = 0x5f }, | ||
578 | { .rfmax = 385000, .val = 0x60 }, | ||
579 | { .rfmax = 386000, .val = 0x61 }, | ||
580 | { .rfmax = 388000, .val = 0x62 }, | ||
581 | { .rfmax = 390000, .val = 0x63 }, | ||
582 | { .rfmax = 393000, .val = 0x64 }, | ||
583 | { .rfmax = 394000, .val = 0x65 }, | ||
584 | { .rfmax = 396000, .val = 0x66 }, | ||
585 | { .rfmax = 397000, .val = 0x67 }, | ||
586 | { .rfmax = 398000, .val = 0x68 }, | ||
587 | { .rfmax = 400000, .val = 0x69 }, | ||
588 | { .rfmax = 402000, .val = 0x6a }, | ||
589 | { .rfmax = 403000, .val = 0x6b }, | ||
590 | { .rfmax = 407000, .val = 0x6c }, | ||
591 | { .rfmax = 408000, .val = 0x6d }, | ||
592 | { .rfmax = 409000, .val = 0x6e }, | ||
593 | { .rfmax = 410000, .val = 0x6f }, | ||
594 | { .rfmax = 411000, .val = 0x70 }, | ||
595 | { .rfmax = 412000, .val = 0x71 }, | ||
596 | { .rfmax = 413000, .val = 0x72 }, | ||
597 | { .rfmax = 414000, .val = 0x73 }, | ||
598 | { .rfmax = 417000, .val = 0x74 }, | ||
599 | { .rfmax = 418000, .val = 0x75 }, | ||
600 | { .rfmax = 420000, .val = 0x76 }, | ||
601 | { .rfmax = 422000, .val = 0x77 }, | ||
602 | { .rfmax = 423000, .val = 0x78 }, | ||
603 | { .rfmax = 424000, .val = 0x79 }, | ||
604 | { .rfmax = 427000, .val = 0x7a }, | ||
605 | { .rfmax = 428000, .val = 0x7b }, | ||
606 | { .rfmax = 429000, .val = 0x7d }, | ||
607 | { .rfmax = 432000, .val = 0x7f }, | ||
608 | { .rfmax = 434000, .val = 0x80 }, | ||
609 | { .rfmax = 435000, .val = 0x81 }, | ||
610 | { .rfmax = 436000, .val = 0x83 }, | ||
611 | { .rfmax = 437000, .val = 0x84 }, | ||
612 | { .rfmax = 438000, .val = 0x85 }, | ||
613 | { .rfmax = 439000, .val = 0x86 }, | ||
614 | { .rfmax = 440000, .val = 0x87 }, | ||
615 | { .rfmax = 441000, .val = 0x88 }, | ||
616 | { .rfmax = 442000, .val = 0x89 }, | ||
617 | { .rfmax = 445000, .val = 0x8a }, | ||
618 | { .rfmax = 446000, .val = 0x8b }, | ||
619 | { .rfmax = 447000, .val = 0x8c }, | ||
620 | { .rfmax = 448000, .val = 0x8e }, | ||
621 | { .rfmax = 449000, .val = 0x8f }, | ||
622 | { .rfmax = 450000, .val = 0x90 }, | ||
623 | { .rfmax = 452000, .val = 0x91 }, | ||
624 | { .rfmax = 453000, .val = 0x93 }, | ||
625 | { .rfmax = 454000, .val = 0x94 }, | ||
626 | { .rfmax = 456000, .val = 0x96 }, | ||
627 | { .rfmax = 457800, .val = 0x98 }, | ||
628 | { .rfmax = 461000, .val = 0x11 }, | ||
629 | { .rfmax = 468000, .val = 0x12 }, | ||
630 | { .rfmax = 472000, .val = 0x13 }, | ||
631 | { .rfmax = 473000, .val = 0x14 }, | ||
632 | { .rfmax = 474000, .val = 0x15 }, | ||
633 | { .rfmax = 481000, .val = 0x16 }, | ||
634 | { .rfmax = 486000, .val = 0x17 }, | ||
635 | { .rfmax = 491000, .val = 0x18 }, | ||
636 | { .rfmax = 498000, .val = 0x19 }, | ||
637 | { .rfmax = 499000, .val = 0x1a }, | ||
638 | { .rfmax = 501000, .val = 0x1b }, | ||
639 | { .rfmax = 506000, .val = 0x1c }, | ||
640 | { .rfmax = 511000, .val = 0x1d }, | ||
641 | { .rfmax = 516000, .val = 0x1e }, | ||
642 | { .rfmax = 520000, .val = 0x1f }, | ||
643 | { .rfmax = 521000, .val = 0x20 }, | ||
644 | { .rfmax = 525000, .val = 0x21 }, | ||
645 | { .rfmax = 529000, .val = 0x22 }, | ||
646 | { .rfmax = 533000, .val = 0x23 }, | ||
647 | { .rfmax = 539000, .val = 0x24 }, | ||
648 | { .rfmax = 541000, .val = 0x25 }, | ||
649 | { .rfmax = 547000, .val = 0x26 }, | ||
650 | { .rfmax = 549000, .val = 0x27 }, | ||
651 | { .rfmax = 551000, .val = 0x28 }, | ||
652 | { .rfmax = 556000, .val = 0x29 }, | ||
653 | { .rfmax = 561000, .val = 0x2a }, | ||
654 | { .rfmax = 563000, .val = 0x2b }, | ||
655 | { .rfmax = 565000, .val = 0x2c }, | ||
656 | { .rfmax = 569000, .val = 0x2d }, | ||
657 | { .rfmax = 571000, .val = 0x2e }, | ||
658 | { .rfmax = 577000, .val = 0x2f }, | ||
659 | { .rfmax = 580000, .val = 0x30 }, | ||
660 | { .rfmax = 582000, .val = 0x31 }, | ||
661 | { .rfmax = 584000, .val = 0x32 }, | ||
662 | { .rfmax = 588000, .val = 0x33 }, | ||
663 | { .rfmax = 591000, .val = 0x34 }, | ||
664 | { .rfmax = 596000, .val = 0x35 }, | ||
665 | { .rfmax = 598000, .val = 0x36 }, | ||
666 | { .rfmax = 603000, .val = 0x37 }, | ||
667 | { .rfmax = 604000, .val = 0x38 }, | ||
668 | { .rfmax = 606000, .val = 0x39 }, | ||
669 | { .rfmax = 612000, .val = 0x3a }, | ||
670 | { .rfmax = 615000, .val = 0x3b }, | ||
671 | { .rfmax = 617000, .val = 0x3c }, | ||
672 | { .rfmax = 621000, .val = 0x3d }, | ||
673 | { .rfmax = 622000, .val = 0x3e }, | ||
674 | { .rfmax = 625000, .val = 0x3f }, | ||
675 | { .rfmax = 632000, .val = 0x40 }, | ||
676 | { .rfmax = 633000, .val = 0x41 }, | ||
677 | { .rfmax = 634000, .val = 0x42 }, | ||
678 | { .rfmax = 642000, .val = 0x43 }, | ||
679 | { .rfmax = 643000, .val = 0x44 }, | ||
680 | { .rfmax = 647000, .val = 0x45 }, | ||
681 | { .rfmax = 650000, .val = 0x46 }, | ||
682 | { .rfmax = 652000, .val = 0x47 }, | ||
683 | { .rfmax = 657000, .val = 0x48 }, | ||
684 | { .rfmax = 661000, .val = 0x49 }, | ||
685 | { .rfmax = 662000, .val = 0x4a }, | ||
686 | { .rfmax = 665000, .val = 0x4b }, | ||
687 | { .rfmax = 667000, .val = 0x4c }, | ||
688 | { .rfmax = 670000, .val = 0x4d }, | ||
689 | { .rfmax = 673000, .val = 0x4e }, | ||
690 | { .rfmax = 676000, .val = 0x4f }, | ||
691 | { .rfmax = 677000, .val = 0x50 }, | ||
692 | { .rfmax = 681000, .val = 0x51 }, | ||
693 | { .rfmax = 683000, .val = 0x52 }, | ||
694 | { .rfmax = 686000, .val = 0x53 }, | ||
695 | { .rfmax = 688000, .val = 0x54 }, | ||
696 | { .rfmax = 689000, .val = 0x55 }, | ||
697 | { .rfmax = 691000, .val = 0x56 }, | ||
698 | { .rfmax = 695000, .val = 0x57 }, | ||
699 | { .rfmax = 698000, .val = 0x58 }, | ||
700 | { .rfmax = 703000, .val = 0x59 }, | ||
701 | { .rfmax = 704000, .val = 0x5a }, | ||
702 | { .rfmax = 705000, .val = 0x5b }, | ||
703 | { .rfmax = 707000, .val = 0x5c }, | ||
704 | { .rfmax = 710000, .val = 0x5d }, | ||
705 | { .rfmax = 712000, .val = 0x5e }, | ||
706 | { .rfmax = 717000, .val = 0x5f }, | ||
707 | { .rfmax = 718000, .val = 0x60 }, | ||
708 | { .rfmax = 721000, .val = 0x61 }, | ||
709 | { .rfmax = 722000, .val = 0x62 }, | ||
710 | { .rfmax = 723000, .val = 0x63 }, | ||
711 | { .rfmax = 725000, .val = 0x64 }, | ||
712 | { .rfmax = 727000, .val = 0x65 }, | ||
713 | { .rfmax = 730000, .val = 0x66 }, | ||
714 | { .rfmax = 732000, .val = 0x67 }, | ||
715 | { .rfmax = 735000, .val = 0x68 }, | ||
716 | { .rfmax = 740000, .val = 0x69 }, | ||
717 | { .rfmax = 741000, .val = 0x6a }, | ||
718 | { .rfmax = 742000, .val = 0x6b }, | ||
719 | { .rfmax = 743000, .val = 0x6c }, | ||
720 | { .rfmax = 745000, .val = 0x6d }, | ||
721 | { .rfmax = 747000, .val = 0x6e }, | ||
722 | { .rfmax = 748000, .val = 0x6f }, | ||
723 | { .rfmax = 750000, .val = 0x70 }, | ||
724 | { .rfmax = 752000, .val = 0x71 }, | ||
725 | { .rfmax = 754000, .val = 0x72 }, | ||
726 | { .rfmax = 757000, .val = 0x73 }, | ||
727 | { .rfmax = 758000, .val = 0x74 }, | ||
728 | { .rfmax = 760000, .val = 0x75 }, | ||
729 | { .rfmax = 763000, .val = 0x76 }, | ||
730 | { .rfmax = 764000, .val = 0x77 }, | ||
731 | { .rfmax = 766000, .val = 0x78 }, | ||
732 | { .rfmax = 767000, .val = 0x79 }, | ||
733 | { .rfmax = 768000, .val = 0x7a }, | ||
734 | { .rfmax = 773000, .val = 0x7b }, | ||
735 | { .rfmax = 774000, .val = 0x7c }, | ||
736 | { .rfmax = 776000, .val = 0x7d }, | ||
737 | { .rfmax = 777000, .val = 0x7e }, | ||
738 | { .rfmax = 778000, .val = 0x7f }, | ||
739 | { .rfmax = 779000, .val = 0x80 }, | ||
740 | { .rfmax = 781000, .val = 0x81 }, | ||
741 | { .rfmax = 783000, .val = 0x82 }, | ||
742 | { .rfmax = 784000, .val = 0x83 }, | ||
743 | { .rfmax = 785000, .val = 0x84 }, | ||
744 | { .rfmax = 786000, .val = 0x85 }, | ||
745 | { .rfmax = 793000, .val = 0x86 }, | ||
746 | { .rfmax = 794000, .val = 0x87 }, | ||
747 | { .rfmax = 795000, .val = 0x88 }, | ||
748 | { .rfmax = 797000, .val = 0x89 }, | ||
749 | { .rfmax = 799000, .val = 0x8a }, | ||
750 | { .rfmax = 801000, .val = 0x8b }, | ||
751 | { .rfmax = 802000, .val = 0x8c }, | ||
752 | { .rfmax = 803000, .val = 0x8d }, | ||
753 | { .rfmax = 804000, .val = 0x8e }, | ||
754 | { .rfmax = 810000, .val = 0x90 }, | ||
755 | { .rfmax = 811000, .val = 0x91 }, | ||
756 | { .rfmax = 812000, .val = 0x92 }, | ||
757 | { .rfmax = 814000, .val = 0x93 }, | ||
758 | { .rfmax = 816000, .val = 0x94 }, | ||
759 | { .rfmax = 817000, .val = 0x96 }, | ||
760 | { .rfmax = 818000, .val = 0x97 }, | ||
761 | { .rfmax = 820000, .val = 0x98 }, | ||
762 | { .rfmax = 821000, .val = 0x99 }, | ||
763 | { .rfmax = 822000, .val = 0x9a }, | ||
764 | { .rfmax = 828000, .val = 0x9b }, | ||
765 | { .rfmax = 829000, .val = 0x9d }, | ||
766 | { .rfmax = 830000, .val = 0x9f }, | ||
767 | { .rfmax = 831000, .val = 0xa0 }, | ||
768 | { .rfmax = 833000, .val = 0xa1 }, | ||
769 | { .rfmax = 835000, .val = 0xa2 }, | ||
770 | { .rfmax = 836000, .val = 0xa3 }, | ||
771 | { .rfmax = 837000, .val = 0xa4 }, | ||
772 | { .rfmax = 838000, .val = 0xa6 }, | ||
773 | { .rfmax = 840000, .val = 0xa8 }, | ||
774 | { .rfmax = 842000, .val = 0xa9 }, | ||
775 | { .rfmax = 845000, .val = 0xaa }, | ||
776 | { .rfmax = 846000, .val = 0xab }, | ||
777 | { .rfmax = 847000, .val = 0xad }, | ||
778 | { .rfmax = 848000, .val = 0xae }, | ||
779 | { .rfmax = 852000, .val = 0xaf }, | ||
780 | { .rfmax = 853000, .val = 0xb0 }, | ||
781 | { .rfmax = 858000, .val = 0xb1 }, | ||
782 | { .rfmax = 860000, .val = 0xb2 }, | ||
783 | { .rfmax = 861000, .val = 0xb3 }, | ||
784 | { .rfmax = 862000, .val = 0xb4 }, | ||
785 | { .rfmax = 863000, .val = 0xb6 }, | ||
786 | { .rfmax = 864000, .val = 0xb8 }, | ||
787 | { .rfmax = 865000, .val = 0xb9 }, | ||
788 | { .rfmax = 0, .val = 0x00 }, /* end */ | ||
789 | }; | ||
790 | |||
791 | static struct tda18271_map tda18271_ir_measure[] = { | ||
792 | { .rfmax = 30000, .val = 4 }, | ||
793 | { .rfmax = 200000, .val = 5 }, | ||
794 | { .rfmax = 600000, .val = 6 }, | ||
795 | { .rfmax = 865000, .val = 7 }, | ||
796 | { .rfmax = 0, .val = 0 }, /* end */ | ||
797 | }; | ||
798 | |||
799 | static struct tda18271_map tda18271_rf_cal_dc_over_dt[] = { | ||
800 | { .rfmax = 47900, .val = 0x00 }, | ||
801 | { .rfmax = 55000, .val = 0x00 }, | ||
802 | { .rfmax = 61100, .val = 0x0a }, | ||
803 | { .rfmax = 64000, .val = 0x0a }, | ||
804 | { .rfmax = 82000, .val = 0x14 }, | ||
805 | { .rfmax = 84000, .val = 0x19 }, | ||
806 | { .rfmax = 119000, .val = 0x1c }, | ||
807 | { .rfmax = 124000, .val = 0x20 }, | ||
808 | { .rfmax = 129000, .val = 0x2a }, | ||
809 | { .rfmax = 134000, .val = 0x32 }, | ||
810 | { .rfmax = 139000, .val = 0x39 }, | ||
811 | { .rfmax = 144000, .val = 0x3e }, | ||
812 | { .rfmax = 149000, .val = 0x3f }, | ||
813 | { .rfmax = 152600, .val = 0x40 }, | ||
814 | { .rfmax = 154000, .val = 0x40 }, | ||
815 | { .rfmax = 164700, .val = 0x41 }, | ||
816 | { .rfmax = 203500, .val = 0x32 }, | ||
817 | { .rfmax = 353000, .val = 0x19 }, | ||
818 | { .rfmax = 356000, .val = 0x1a }, | ||
819 | { .rfmax = 359000, .val = 0x1b }, | ||
820 | { .rfmax = 363000, .val = 0x1c }, | ||
821 | { .rfmax = 366000, .val = 0x1d }, | ||
822 | { .rfmax = 369000, .val = 0x1e }, | ||
823 | { .rfmax = 373000, .val = 0x1f }, | ||
824 | { .rfmax = 376000, .val = 0x20 }, | ||
825 | { .rfmax = 379000, .val = 0x21 }, | ||
826 | { .rfmax = 383000, .val = 0x22 }, | ||
827 | { .rfmax = 386000, .val = 0x23 }, | ||
828 | { .rfmax = 389000, .val = 0x24 }, | ||
829 | { .rfmax = 393000, .val = 0x25 }, | ||
830 | { .rfmax = 396000, .val = 0x26 }, | ||
831 | { .rfmax = 399000, .val = 0x27 }, | ||
832 | { .rfmax = 402000, .val = 0x28 }, | ||
833 | { .rfmax = 404000, .val = 0x29 }, | ||
834 | { .rfmax = 407000, .val = 0x2a }, | ||
835 | { .rfmax = 409000, .val = 0x2b }, | ||
836 | { .rfmax = 412000, .val = 0x2c }, | ||
837 | { .rfmax = 414000, .val = 0x2d }, | ||
838 | { .rfmax = 417000, .val = 0x2e }, | ||
839 | { .rfmax = 419000, .val = 0x2f }, | ||
840 | { .rfmax = 422000, .val = 0x30 }, | ||
841 | { .rfmax = 424000, .val = 0x31 }, | ||
842 | { .rfmax = 427000, .val = 0x32 }, | ||
843 | { .rfmax = 429000, .val = 0x33 }, | ||
844 | { .rfmax = 432000, .val = 0x34 }, | ||
845 | { .rfmax = 434000, .val = 0x35 }, | ||
846 | { .rfmax = 437000, .val = 0x36 }, | ||
847 | { .rfmax = 439000, .val = 0x37 }, | ||
848 | { .rfmax = 442000, .val = 0x38 }, | ||
849 | { .rfmax = 444000, .val = 0x39 }, | ||
850 | { .rfmax = 447000, .val = 0x3a }, | ||
851 | { .rfmax = 449000, .val = 0x3b }, | ||
852 | { .rfmax = 457800, .val = 0x3c }, | ||
853 | { .rfmax = 465000, .val = 0x0f }, | ||
854 | { .rfmax = 477000, .val = 0x12 }, | ||
855 | { .rfmax = 483000, .val = 0x14 }, | ||
856 | { .rfmax = 502000, .val = 0x19 }, | ||
857 | { .rfmax = 508000, .val = 0x1b }, | ||
858 | { .rfmax = 519000, .val = 0x1c }, | ||
859 | { .rfmax = 522000, .val = 0x1d }, | ||
860 | { .rfmax = 524000, .val = 0x1e }, | ||
861 | { .rfmax = 534000, .val = 0x1f }, | ||
862 | { .rfmax = 549000, .val = 0x20 }, | ||
863 | { .rfmax = 554000, .val = 0x22 }, | ||
864 | { .rfmax = 584000, .val = 0x24 }, | ||
865 | { .rfmax = 589000, .val = 0x26 }, | ||
866 | { .rfmax = 658000, .val = 0x27 }, | ||
867 | { .rfmax = 664000, .val = 0x2c }, | ||
868 | { .rfmax = 669000, .val = 0x2d }, | ||
869 | { .rfmax = 699000, .val = 0x2e }, | ||
870 | { .rfmax = 704000, .val = 0x30 }, | ||
871 | { .rfmax = 709000, .val = 0x31 }, | ||
872 | { .rfmax = 714000, .val = 0x32 }, | ||
873 | { .rfmax = 724000, .val = 0x33 }, | ||
874 | { .rfmax = 729000, .val = 0x36 }, | ||
875 | { .rfmax = 739000, .val = 0x38 }, | ||
876 | { .rfmax = 744000, .val = 0x39 }, | ||
877 | { .rfmax = 749000, .val = 0x3b }, | ||
878 | { .rfmax = 754000, .val = 0x3c }, | ||
879 | { .rfmax = 759000, .val = 0x3d }, | ||
880 | { .rfmax = 764000, .val = 0x3e }, | ||
881 | { .rfmax = 769000, .val = 0x3f }, | ||
882 | { .rfmax = 774000, .val = 0x40 }, | ||
883 | { .rfmax = 779000, .val = 0x41 }, | ||
884 | { .rfmax = 784000, .val = 0x43 }, | ||
885 | { .rfmax = 789000, .val = 0x46 }, | ||
886 | { .rfmax = 794000, .val = 0x48 }, | ||
887 | { .rfmax = 799000, .val = 0x4b }, | ||
888 | { .rfmax = 804000, .val = 0x4f }, | ||
889 | { .rfmax = 809000, .val = 0x54 }, | ||
890 | { .rfmax = 814000, .val = 0x59 }, | ||
891 | { .rfmax = 819000, .val = 0x5d }, | ||
892 | { .rfmax = 824000, .val = 0x61 }, | ||
893 | { .rfmax = 829000, .val = 0x68 }, | ||
894 | { .rfmax = 834000, .val = 0x6e }, | ||
895 | { .rfmax = 839000, .val = 0x75 }, | ||
896 | { .rfmax = 844000, .val = 0x7e }, | ||
897 | { .rfmax = 849000, .val = 0x82 }, | ||
898 | { .rfmax = 854000, .val = 0x84 }, | ||
899 | { .rfmax = 859000, .val = 0x8f }, | ||
900 | { .rfmax = 865000, .val = 0x9a }, | ||
901 | { .rfmax = 0, .val = 0x00 }, /* end */ | ||
902 | }; | ||
903 | |||
904 | /*---------------------------------------------------------------------*/ | ||
905 | |||
906 | struct tda18271_thermo_map { | ||
907 | u8 d; | ||
908 | u8 r0; | ||
909 | u8 r1; | ||
910 | }; | ||
911 | |||
912 | static struct tda18271_thermo_map tda18271_thermometer[] = { | ||
913 | { .d = 0x00, .r0 = 60, .r1 = 92 }, | ||
914 | { .d = 0x01, .r0 = 62, .r1 = 94 }, | ||
915 | { .d = 0x02, .r0 = 66, .r1 = 98 }, | ||
916 | { .d = 0x03, .r0 = 64, .r1 = 96 }, | ||
917 | { .d = 0x04, .r0 = 74, .r1 = 106 }, | ||
918 | { .d = 0x05, .r0 = 72, .r1 = 104 }, | ||
919 | { .d = 0x06, .r0 = 68, .r1 = 100 }, | ||
920 | { .d = 0x07, .r0 = 70, .r1 = 102 }, | ||
921 | { .d = 0x08, .r0 = 90, .r1 = 122 }, | ||
922 | { .d = 0x09, .r0 = 88, .r1 = 120 }, | ||
923 | { .d = 0x0a, .r0 = 84, .r1 = 116 }, | ||
924 | { .d = 0x0b, .r0 = 86, .r1 = 118 }, | ||
925 | { .d = 0x0c, .r0 = 76, .r1 = 108 }, | ||
926 | { .d = 0x0d, .r0 = 78, .r1 = 110 }, | ||
927 | { .d = 0x0e, .r0 = 82, .r1 = 114 }, | ||
928 | { .d = 0x0f, .r0 = 80, .r1 = 112 }, | ||
929 | { .d = 0x00, .r0 = 0, .r1 = 0 }, /* end */ | ||
930 | }; | ||
931 | |||
932 | int tda18271_lookup_thermometer(struct dvb_frontend *fe) | ||
933 | { | ||
934 | struct tda18271_priv *priv = fe->tuner_priv; | ||
935 | unsigned char *regs = priv->tda18271_regs; | ||
936 | int val, i = 0; | ||
937 | |||
938 | while (tda18271_thermometer[i].d < (regs[R_TM] & 0x0f)) { | ||
939 | if (tda18271_thermometer[i + 1].d == 0) | ||
940 | break; | ||
941 | i++; | ||
942 | } | ||
943 | |||
944 | if ((regs[R_TM] & 0x20) == 0x20) | ||
945 | val = tda18271_thermometer[i].r1; | ||
946 | else | ||
947 | val = tda18271_thermometer[i].r0; | ||
948 | |||
949 | tda_map("(%d) tm = %d\n", i, val); | ||
950 | |||
951 | return val; | ||
952 | } | ||
953 | |||
954 | /*---------------------------------------------------------------------*/ | ||
955 | |||
956 | struct tda18271_cid_target_map { | ||
957 | u32 rfmax; | ||
958 | u8 target; | ||
959 | u16 limit; | ||
960 | }; | ||
961 | |||
962 | static struct tda18271_cid_target_map tda18271_cid_target[] = { | ||
963 | { .rfmax = 46000, .target = 0x04, .limit = 1800 }, | ||
964 | { .rfmax = 52200, .target = 0x0a, .limit = 1500 }, | ||
965 | { .rfmax = 70100, .target = 0x01, .limit = 4000 }, | ||
966 | { .rfmax = 136800, .target = 0x18, .limit = 4000 }, | ||
967 | { .rfmax = 156700, .target = 0x18, .limit = 4000 }, | ||
968 | { .rfmax = 186250, .target = 0x0a, .limit = 4000 }, | ||
969 | { .rfmax = 230000, .target = 0x0a, .limit = 4000 }, | ||
970 | { .rfmax = 345000, .target = 0x18, .limit = 4000 }, | ||
971 | { .rfmax = 426000, .target = 0x0e, .limit = 4000 }, | ||
972 | { .rfmax = 489500, .target = 0x1e, .limit = 4000 }, | ||
973 | { .rfmax = 697500, .target = 0x32, .limit = 4000 }, | ||
974 | { .rfmax = 842000, .target = 0x3a, .limit = 4000 }, | ||
975 | { .rfmax = 0, .target = 0x00, .limit = 0 }, /* end */ | ||
976 | }; | ||
977 | |||
978 | int tda18271_lookup_cid_target(struct dvb_frontend *fe, | ||
979 | u32 *freq, u8 *cid_target, u16 *count_limit) | ||
980 | { | ||
981 | struct tda18271_priv *priv = fe->tuner_priv; | ||
982 | int i = 0; | ||
983 | |||
984 | while ((tda18271_cid_target[i].rfmax * 1000) < *freq) { | ||
985 | if (tda18271_cid_target[i + 1].rfmax == 0) | ||
986 | break; | ||
987 | i++; | ||
988 | } | ||
989 | *cid_target = tda18271_cid_target[i].target; | ||
990 | *count_limit = tda18271_cid_target[i].limit; | ||
991 | |||
992 | tda_map("(%d) cid_target = %02x, count_limit = %d\n", i, | ||
993 | tda18271_cid_target[i].target, tda18271_cid_target[i].limit); | ||
994 | |||
995 | return 0; | ||
996 | } | ||
997 | |||
998 | /*---------------------------------------------------------------------*/ | ||
999 | |||
1000 | static struct tda18271_rf_tracking_filter_cal tda18271_rf_band_template[] = { | ||
1001 | { .rfmax = 47900, .rfband = 0x00, | ||
1002 | .rf1_def = 46000, .rf2_def = 0, .rf3_def = 0 }, | ||
1003 | { .rfmax = 61100, .rfband = 0x01, | ||
1004 | .rf1_def = 52200, .rf2_def = 0, .rf3_def = 0 }, | ||
1005 | { .rfmax = 152600, .rfband = 0x02, | ||
1006 | .rf1_def = 70100, .rf2_def = 136800, .rf3_def = 0 }, | ||
1007 | { .rfmax = 164700, .rfband = 0x03, | ||
1008 | .rf1_def = 156700, .rf2_def = 0, .rf3_def = 0 }, | ||
1009 | { .rfmax = 203500, .rfband = 0x04, | ||
1010 | .rf1_def = 186250, .rf2_def = 0, .rf3_def = 0 }, | ||
1011 | { .rfmax = 457800, .rfband = 0x05, | ||
1012 | .rf1_def = 230000, .rf2_def = 345000, .rf3_def = 426000 }, | ||
1013 | { .rfmax = 865000, .rfband = 0x06, | ||
1014 | .rf1_def = 489500, .rf2_def = 697500, .rf3_def = 842000 }, | ||
1015 | { .rfmax = 0, .rfband = 0x00, | ||
1016 | .rf1_def = 0, .rf2_def = 0, .rf3_def = 0 }, /* end */ | ||
1017 | }; | ||
1018 | |||
1019 | int tda18271_lookup_rf_band(struct dvb_frontend *fe, u32 *freq, u8 *rf_band) | ||
1020 | { | ||
1021 | struct tda18271_priv *priv = fe->tuner_priv; | ||
1022 | struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state; | ||
1023 | int i = 0; | ||
1024 | |||
1025 | while ((map[i].rfmax * 1000) < *freq) { | ||
1026 | if (tda18271_debug & DBG_ADV) | ||
1027 | tda_map("(%d) rfmax = %d < freq = %d, " | ||
1028 | "rf1_def = %d, rf2_def = %d, rf3_def = %d, " | ||
1029 | "rf1 = %d, rf2 = %d, rf3 = %d, " | ||
1030 | "rf_a1 = %d, rf_a2 = %d, " | ||
1031 | "rf_b1 = %d, rf_b2 = %d\n", | ||
1032 | i, map[i].rfmax * 1000, *freq, | ||
1033 | map[i].rf1_def, map[i].rf2_def, map[i].rf3_def, | ||
1034 | map[i].rf1, map[i].rf2, map[i].rf3, | ||
1035 | map[i].rf_a1, map[i].rf_a2, | ||
1036 | map[i].rf_b1, map[i].rf_b2); | ||
1037 | if (map[i].rfmax == 0) | ||
1038 | return -EINVAL; | ||
1039 | i++; | ||
1040 | } | ||
1041 | if (rf_band) | ||
1042 | *rf_band = map[i].rfband; | ||
1043 | |||
1044 | tda_map("(%d) rf_band = %02x\n", i, map[i].rfband); | ||
1045 | |||
1046 | return i; | ||
1047 | } | ||
1048 | |||
1049 | /*---------------------------------------------------------------------*/ | ||
1050 | |||
1051 | struct tda18271_map_layout { | ||
1052 | struct tda18271_pll_map *main_pll; | ||
1053 | struct tda18271_pll_map *cal_pll; | ||
1054 | |||
1055 | struct tda18271_map *rf_cal; | ||
1056 | struct tda18271_map *rf_cal_kmco; | ||
1057 | struct tda18271_map *rf_cal_dc_over_dt; | ||
1058 | |||
1059 | struct tda18271_map *bp_filter; | ||
1060 | struct tda18271_map *rf_band; | ||
1061 | struct tda18271_map *gain_taper; | ||
1062 | struct tda18271_map *ir_measure; | ||
1063 | }; | ||
1064 | |||
1065 | /*---------------------------------------------------------------------*/ | ||
1066 | |||
1067 | int tda18271_lookup_pll_map(struct dvb_frontend *fe, | ||
1068 | enum tda18271_map_type map_type, | ||
1069 | u32 *freq, u8 *post_div, u8 *div) | ||
1070 | { | ||
1071 | struct tda18271_priv *priv = fe->tuner_priv; | ||
1072 | struct tda18271_pll_map *map = NULL; | ||
1073 | unsigned int i = 0; | ||
1074 | char *map_name; | ||
1075 | int ret = 0; | ||
1076 | |||
1077 | BUG_ON(!priv->maps); | ||
1078 | |||
1079 | switch (map_type) { | ||
1080 | case MAIN_PLL: | ||
1081 | map = priv->maps->main_pll; | ||
1082 | map_name = "main_pll"; | ||
1083 | break; | ||
1084 | case CAL_PLL: | ||
1085 | map = priv->maps->cal_pll; | ||
1086 | map_name = "cal_pll"; | ||
1087 | break; | ||
1088 | default: | ||
1089 | /* we should never get here */ | ||
1090 | map_name = "undefined"; | ||
1091 | break; | ||
1092 | } | ||
1093 | |||
1094 | if (!map) { | ||
1095 | tda_warn("%s map is not set!\n", map_name); | ||
1096 | ret = -EINVAL; | ||
1097 | goto fail; | ||
1098 | } | ||
1099 | |||
1100 | while ((map[i].lomax * 1000) < *freq) { | ||
1101 | if (map[i + 1].lomax == 0) { | ||
1102 | tda_map("%s: frequency (%d) out of range\n", | ||
1103 | map_name, *freq); | ||
1104 | ret = -ERANGE; | ||
1105 | break; | ||
1106 | } | ||
1107 | i++; | ||
1108 | } | ||
1109 | *post_div = map[i].pd; | ||
1110 | *div = map[i].d; | ||
1111 | |||
1112 | tda_map("(%d) %s: post div = 0x%02x, div = 0x%02x\n", | ||
1113 | i, map_name, *post_div, *div); | ||
1114 | fail: | ||
1115 | return ret; | ||
1116 | } | ||
1117 | |||
1118 | int tda18271_lookup_map(struct dvb_frontend *fe, | ||
1119 | enum tda18271_map_type map_type, | ||
1120 | u32 *freq, u8 *val) | ||
1121 | { | ||
1122 | struct tda18271_priv *priv = fe->tuner_priv; | ||
1123 | struct tda18271_map *map = NULL; | ||
1124 | unsigned int i = 0; | ||
1125 | char *map_name; | ||
1126 | int ret = 0; | ||
1127 | |||
1128 | BUG_ON(!priv->maps); | ||
1129 | |||
1130 | switch (map_type) { | ||
1131 | case BP_FILTER: | ||
1132 | map = priv->maps->bp_filter; | ||
1133 | map_name = "bp_filter"; | ||
1134 | break; | ||
1135 | case RF_CAL_KMCO: | ||
1136 | map = priv->maps->rf_cal_kmco; | ||
1137 | map_name = "km"; | ||
1138 | break; | ||
1139 | case RF_BAND: | ||
1140 | map = priv->maps->rf_band; | ||
1141 | map_name = "rf_band"; | ||
1142 | break; | ||
1143 | case GAIN_TAPER: | ||
1144 | map = priv->maps->gain_taper; | ||
1145 | map_name = "gain_taper"; | ||
1146 | break; | ||
1147 | case RF_CAL: | ||
1148 | map = priv->maps->rf_cal; | ||
1149 | map_name = "rf_cal"; | ||
1150 | break; | ||
1151 | case IR_MEASURE: | ||
1152 | map = priv->maps->ir_measure; | ||
1153 | map_name = "ir_measure"; | ||
1154 | break; | ||
1155 | case RF_CAL_DC_OVER_DT: | ||
1156 | map = priv->maps->rf_cal_dc_over_dt; | ||
1157 | map_name = "rf_cal_dc_over_dt"; | ||
1158 | break; | ||
1159 | default: | ||
1160 | /* we should never get here */ | ||
1161 | map_name = "undefined"; | ||
1162 | break; | ||
1163 | } | ||
1164 | |||
1165 | if (!map) { | ||
1166 | tda_warn("%s map is not set!\n", map_name); | ||
1167 | ret = -EINVAL; | ||
1168 | goto fail; | ||
1169 | } | ||
1170 | |||
1171 | while ((map[i].rfmax * 1000) < *freq) { | ||
1172 | if (map[i + 1].rfmax == 0) { | ||
1173 | tda_map("%s: frequency (%d) out of range\n", | ||
1174 | map_name, *freq); | ||
1175 | ret = -ERANGE; | ||
1176 | break; | ||
1177 | } | ||
1178 | i++; | ||
1179 | } | ||
1180 | *val = map[i].val; | ||
1181 | |||
1182 | tda_map("(%d) %s: 0x%02x\n", i, map_name, *val); | ||
1183 | fail: | ||
1184 | return ret; | ||
1185 | } | ||
1186 | |||
1187 | /*---------------------------------------------------------------------*/ | ||
1188 | |||
1189 | static struct tda18271_std_map tda18271c1_std_map = { | ||
1190 | .fm_radio = { .if_freq = 1250, .fm_rfn = 1, .agc_mode = 3, .std = 0, | ||
1191 | .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x18 */ | ||
1192 | .atv_b = { .if_freq = 6750, .fm_rfn = 0, .agc_mode = 1, .std = 6, | ||
1193 | .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ | ||
1194 | .atv_dk = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7, | ||
1195 | .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */ | ||
1196 | .atv_gh = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7, | ||
1197 | .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */ | ||
1198 | .atv_i = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7, | ||
1199 | .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */ | ||
1200 | .atv_l = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7, | ||
1201 | .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */ | ||
1202 | .atv_lc = { .if_freq = 1250, .fm_rfn = 0, .agc_mode = 1, .std = 7, | ||
1203 | .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */ | ||
1204 | .atv_mn = { .if_freq = 5750, .fm_rfn = 0, .agc_mode = 1, .std = 5, | ||
1205 | .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0d */ | ||
1206 | .atsc_6 = { .if_freq = 3250, .fm_rfn = 0, .agc_mode = 3, .std = 4, | ||
1207 | .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */ | ||
1208 | .dvbt_6 = { .if_freq = 3300, .fm_rfn = 0, .agc_mode = 3, .std = 4, | ||
1209 | .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */ | ||
1210 | .dvbt_7 = { .if_freq = 3800, .fm_rfn = 0, .agc_mode = 3, .std = 5, | ||
1211 | .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */ | ||
1212 | .dvbt_8 = { .if_freq = 4300, .fm_rfn = 0, .agc_mode = 3, .std = 6, | ||
1213 | .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1e */ | ||
1214 | .qam_6 = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5, | ||
1215 | .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */ | ||
1216 | .qam_7 = { .if_freq = 4500, .fm_rfn = 0, .agc_mode = 3, .std = 6, | ||
1217 | .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1e */ | ||
1218 | .qam_8 = { .if_freq = 5000, .fm_rfn = 0, .agc_mode = 3, .std = 7, | ||
1219 | .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1f */ | ||
1220 | }; | ||
1221 | |||
1222 | static struct tda18271_std_map tda18271c2_std_map = { | ||
1223 | .fm_radio = { .if_freq = 1250, .fm_rfn = 1, .agc_mode = 3, .std = 0, | ||
1224 | .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x18 */ | ||
1225 | .atv_b = { .if_freq = 6000, .fm_rfn = 0, .agc_mode = 1, .std = 5, | ||
1226 | .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0d */ | ||
1227 | .atv_dk = { .if_freq = 6900, .fm_rfn = 0, .agc_mode = 1, .std = 6, | ||
1228 | .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ | ||
1229 | .atv_gh = { .if_freq = 7100, .fm_rfn = 0, .agc_mode = 1, .std = 6, | ||
1230 | .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ | ||
1231 | .atv_i = { .if_freq = 7250, .fm_rfn = 0, .agc_mode = 1, .std = 6, | ||
1232 | .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ | ||
1233 | .atv_l = { .if_freq = 6900, .fm_rfn = 0, .agc_mode = 1, .std = 6, | ||
1234 | .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ | ||
1235 | .atv_lc = { .if_freq = 1250, .fm_rfn = 0, .agc_mode = 1, .std = 6, | ||
1236 | .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */ | ||
1237 | .atv_mn = { .if_freq = 5400, .fm_rfn = 0, .agc_mode = 1, .std = 4, | ||
1238 | .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0c */ | ||
1239 | .atsc_6 = { .if_freq = 3250, .fm_rfn = 0, .agc_mode = 3, .std = 4, | ||
1240 | .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */ | ||
1241 | .dvbt_6 = { .if_freq = 3300, .fm_rfn = 0, .agc_mode = 3, .std = 4, | ||
1242 | .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */ | ||
1243 | .dvbt_7 = { .if_freq = 3500, .fm_rfn = 0, .agc_mode = 3, .std = 4, | ||
1244 | .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */ | ||
1245 | .dvbt_8 = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5, | ||
1246 | .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */ | ||
1247 | .qam_6 = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5, | ||
1248 | .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */ | ||
1249 | .qam_7 = { .if_freq = 4500, .fm_rfn = 0, .agc_mode = 3, .std = 6, | ||
1250 | .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1e */ | ||
1251 | .qam_8 = { .if_freq = 5000, .fm_rfn = 0, .agc_mode = 3, .std = 7, | ||
1252 | .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1f */ | ||
1253 | }; | ||
1254 | |||
1255 | /*---------------------------------------------------------------------*/ | ||
1256 | |||
1257 | static struct tda18271_map_layout tda18271c1_map_layout = { | ||
1258 | .main_pll = tda18271c1_main_pll, | ||
1259 | .cal_pll = tda18271c1_cal_pll, | ||
1260 | |||
1261 | .rf_cal = tda18271c1_rf_cal, | ||
1262 | .rf_cal_kmco = tda18271c1_km, | ||
1263 | |||
1264 | .bp_filter = tda18271_bp_filter, | ||
1265 | .rf_band = tda18271_rf_band, | ||
1266 | .gain_taper = tda18271_gain_taper, | ||
1267 | .ir_measure = tda18271_ir_measure, | ||
1268 | }; | ||
1269 | |||
1270 | static struct tda18271_map_layout tda18271c2_map_layout = { | ||
1271 | .main_pll = tda18271c2_main_pll, | ||
1272 | .cal_pll = tda18271c2_cal_pll, | ||
1273 | |||
1274 | .rf_cal = tda18271c2_rf_cal, | ||
1275 | .rf_cal_kmco = tda18271c2_km, | ||
1276 | |||
1277 | .rf_cal_dc_over_dt = tda18271_rf_cal_dc_over_dt, | ||
1278 | |||
1279 | .bp_filter = tda18271_bp_filter, | ||
1280 | .rf_band = tda18271_rf_band, | ||
1281 | .gain_taper = tda18271_gain_taper, | ||
1282 | .ir_measure = tda18271_ir_measure, | ||
1283 | }; | ||
1284 | |||
1285 | int tda18271_assign_map_layout(struct dvb_frontend *fe) | ||
1286 | { | ||
1287 | struct tda18271_priv *priv = fe->tuner_priv; | ||
1288 | int ret = 0; | ||
1289 | |||
1290 | switch (priv->id) { | ||
1291 | case TDA18271HDC1: | ||
1292 | priv->maps = &tda18271c1_map_layout; | ||
1293 | memcpy(&priv->std, &tda18271c1_std_map, | ||
1294 | sizeof(struct tda18271_std_map)); | ||
1295 | break; | ||
1296 | case TDA18271HDC2: | ||
1297 | priv->maps = &tda18271c2_map_layout; | ||
1298 | memcpy(&priv->std, &tda18271c2_std_map, | ||
1299 | sizeof(struct tda18271_std_map)); | ||
1300 | break; | ||
1301 | default: | ||
1302 | ret = -EINVAL; | ||
1303 | break; | ||
1304 | } | ||
1305 | memcpy(priv->rf_cal_state, &tda18271_rf_band_template, | ||
1306 | sizeof(tda18271_rf_band_template)); | ||
1307 | |||
1308 | return ret; | ||
1309 | } | ||
1310 | |||
1311 | /* | ||
1312 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
1313 | * --------------------------------------------------------------------------- | ||
1314 | * Local variables: | ||
1315 | * c-basic-offset: 8 | ||
1316 | * End: | ||
1317 | */ | ||
diff --git a/drivers/media/tuners/tda18271-priv.h b/drivers/media/tuners/tda18271-priv.h new file mode 100644 index 000000000000..454c152ccaa0 --- /dev/null +++ b/drivers/media/tuners/tda18271-priv.h | |||
@@ -0,0 +1,236 @@ | |||
1 | /* | ||
2 | tda18271-priv.h - private header for the NXP TDA18271 silicon tuner | ||
3 | |||
4 | Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org> | ||
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 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef __TDA18271_PRIV_H__ | ||
22 | #define __TDA18271_PRIV_H__ | ||
23 | |||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/types.h> | ||
26 | #include <linux/mutex.h> | ||
27 | #include "tuner-i2c.h" | ||
28 | #include "tda18271.h" | ||
29 | |||
30 | #define R_ID 0x00 /* ID byte */ | ||
31 | #define R_TM 0x01 /* Thermo byte */ | ||
32 | #define R_PL 0x02 /* Power level byte */ | ||
33 | #define R_EP1 0x03 /* Easy Prog byte 1 */ | ||
34 | #define R_EP2 0x04 /* Easy Prog byte 2 */ | ||
35 | #define R_EP3 0x05 /* Easy Prog byte 3 */ | ||
36 | #define R_EP4 0x06 /* Easy Prog byte 4 */ | ||
37 | #define R_EP5 0x07 /* Easy Prog byte 5 */ | ||
38 | #define R_CPD 0x08 /* Cal Post-Divider byte */ | ||
39 | #define R_CD1 0x09 /* Cal Divider byte 1 */ | ||
40 | #define R_CD2 0x0a /* Cal Divider byte 2 */ | ||
41 | #define R_CD3 0x0b /* Cal Divider byte 3 */ | ||
42 | #define R_MPD 0x0c /* Main Post-Divider byte */ | ||
43 | #define R_MD1 0x0d /* Main Divider byte 1 */ | ||
44 | #define R_MD2 0x0e /* Main Divider byte 2 */ | ||
45 | #define R_MD3 0x0f /* Main Divider byte 3 */ | ||
46 | #define R_EB1 0x10 /* Extended byte 1 */ | ||
47 | #define R_EB2 0x11 /* Extended byte 2 */ | ||
48 | #define R_EB3 0x12 /* Extended byte 3 */ | ||
49 | #define R_EB4 0x13 /* Extended byte 4 */ | ||
50 | #define R_EB5 0x14 /* Extended byte 5 */ | ||
51 | #define R_EB6 0x15 /* Extended byte 6 */ | ||
52 | #define R_EB7 0x16 /* Extended byte 7 */ | ||
53 | #define R_EB8 0x17 /* Extended byte 8 */ | ||
54 | #define R_EB9 0x18 /* Extended byte 9 */ | ||
55 | #define R_EB10 0x19 /* Extended byte 10 */ | ||
56 | #define R_EB11 0x1a /* Extended byte 11 */ | ||
57 | #define R_EB12 0x1b /* Extended byte 12 */ | ||
58 | #define R_EB13 0x1c /* Extended byte 13 */ | ||
59 | #define R_EB14 0x1d /* Extended byte 14 */ | ||
60 | #define R_EB15 0x1e /* Extended byte 15 */ | ||
61 | #define R_EB16 0x1f /* Extended byte 16 */ | ||
62 | #define R_EB17 0x20 /* Extended byte 17 */ | ||
63 | #define R_EB18 0x21 /* Extended byte 18 */ | ||
64 | #define R_EB19 0x22 /* Extended byte 19 */ | ||
65 | #define R_EB20 0x23 /* Extended byte 20 */ | ||
66 | #define R_EB21 0x24 /* Extended byte 21 */ | ||
67 | #define R_EB22 0x25 /* Extended byte 22 */ | ||
68 | #define R_EB23 0x26 /* Extended byte 23 */ | ||
69 | |||
70 | #define TDA18271_NUM_REGS 39 | ||
71 | |||
72 | /*---------------------------------------------------------------------*/ | ||
73 | |||
74 | struct tda18271_rf_tracking_filter_cal { | ||
75 | u32 rfmax; | ||
76 | u8 rfband; | ||
77 | u32 rf1_def; | ||
78 | u32 rf2_def; | ||
79 | u32 rf3_def; | ||
80 | u32 rf1; | ||
81 | u32 rf2; | ||
82 | u32 rf3; | ||
83 | s32 rf_a1; | ||
84 | s32 rf_b1; | ||
85 | s32 rf_a2; | ||
86 | s32 rf_b2; | ||
87 | }; | ||
88 | |||
89 | enum tda18271_pll { | ||
90 | TDA18271_MAIN_PLL, | ||
91 | TDA18271_CAL_PLL, | ||
92 | }; | ||
93 | |||
94 | struct tda18271_map_layout; | ||
95 | |||
96 | enum tda18271_ver { | ||
97 | TDA18271HDC1, | ||
98 | TDA18271HDC2, | ||
99 | }; | ||
100 | |||
101 | struct tda18271_priv { | ||
102 | unsigned char tda18271_regs[TDA18271_NUM_REGS]; | ||
103 | |||
104 | struct list_head hybrid_tuner_instance_list; | ||
105 | struct tuner_i2c_props i2c_props; | ||
106 | |||
107 | enum tda18271_mode mode; | ||
108 | enum tda18271_role role; | ||
109 | enum tda18271_i2c_gate gate; | ||
110 | enum tda18271_ver id; | ||
111 | enum tda18271_output_options output_opt; | ||
112 | enum tda18271_small_i2c small_i2c; | ||
113 | |||
114 | unsigned int config; /* interface to saa713x / tda829x */ | ||
115 | unsigned int cal_initialized:1; | ||
116 | |||
117 | u8 tm_rfcal; | ||
118 | |||
119 | struct tda18271_map_layout *maps; | ||
120 | struct tda18271_std_map std; | ||
121 | struct tda18271_rf_tracking_filter_cal rf_cal_state[8]; | ||
122 | |||
123 | struct mutex lock; | ||
124 | |||
125 | u16 if_freq; | ||
126 | |||
127 | u32 frequency; | ||
128 | u32 bandwidth; | ||
129 | }; | ||
130 | |||
131 | /*---------------------------------------------------------------------*/ | ||
132 | |||
133 | extern int tda18271_debug; | ||
134 | |||
135 | #define DBG_INFO 1 | ||
136 | #define DBG_MAP 2 | ||
137 | #define DBG_REG 4 | ||
138 | #define DBG_ADV 8 | ||
139 | #define DBG_CAL 16 | ||
140 | |||
141 | __attribute__((format(printf, 4, 5))) | ||
142 | int _tda_printk(struct tda18271_priv *state, const char *level, | ||
143 | const char *func, const char *fmt, ...); | ||
144 | |||
145 | #define tda_printk(st, lvl, fmt, arg...) \ | ||
146 | _tda_printk(st, lvl, __func__, fmt, ##arg) | ||
147 | |||
148 | #define tda_dprintk(st, lvl, fmt, arg...) \ | ||
149 | do { \ | ||
150 | if (tda18271_debug & lvl) \ | ||
151 | tda_printk(st, KERN_DEBUG, fmt, ##arg); \ | ||
152 | } while (0) | ||
153 | |||
154 | #define tda_info(fmt, arg...) pr_info(fmt, ##arg) | ||
155 | #define tda_warn(fmt, arg...) tda_printk(priv, KERN_WARNING, fmt, ##arg) | ||
156 | #define tda_err(fmt, arg...) tda_printk(priv, KERN_ERR, fmt, ##arg) | ||
157 | #define tda_dbg(fmt, arg...) tda_dprintk(priv, DBG_INFO, fmt, ##arg) | ||
158 | #define tda_map(fmt, arg...) tda_dprintk(priv, DBG_MAP, fmt, ##arg) | ||
159 | #define tda_reg(fmt, arg...) tda_dprintk(priv, DBG_REG, fmt, ##arg) | ||
160 | #define tda_cal(fmt, arg...) tda_dprintk(priv, DBG_CAL, fmt, ##arg) | ||
161 | |||
162 | #define tda_fail(ret) \ | ||
163 | ({ \ | ||
164 | int __ret; \ | ||
165 | __ret = (ret < 0); \ | ||
166 | if (__ret) \ | ||
167 | tda_printk(priv, KERN_ERR, \ | ||
168 | "error %d on line %d\n", ret, __LINE__); \ | ||
169 | __ret; \ | ||
170 | }) | ||
171 | |||
172 | /*---------------------------------------------------------------------*/ | ||
173 | |||
174 | enum tda18271_map_type { | ||
175 | /* tda18271_pll_map */ | ||
176 | MAIN_PLL, | ||
177 | CAL_PLL, | ||
178 | /* tda18271_map */ | ||
179 | RF_CAL, | ||
180 | RF_CAL_KMCO, | ||
181 | RF_CAL_DC_OVER_DT, | ||
182 | BP_FILTER, | ||
183 | RF_BAND, | ||
184 | GAIN_TAPER, | ||
185 | IR_MEASURE, | ||
186 | }; | ||
187 | |||
188 | extern int tda18271_lookup_pll_map(struct dvb_frontend *fe, | ||
189 | enum tda18271_map_type map_type, | ||
190 | u32 *freq, u8 *post_div, u8 *div); | ||
191 | extern int tda18271_lookup_map(struct dvb_frontend *fe, | ||
192 | enum tda18271_map_type map_type, | ||
193 | u32 *freq, u8 *val); | ||
194 | |||
195 | extern int tda18271_lookup_thermometer(struct dvb_frontend *fe); | ||
196 | |||
197 | extern int tda18271_lookup_rf_band(struct dvb_frontend *fe, | ||
198 | u32 *freq, u8 *rf_band); | ||
199 | |||
200 | extern int tda18271_lookup_cid_target(struct dvb_frontend *fe, | ||
201 | u32 *freq, u8 *cid_target, | ||
202 | u16 *count_limit); | ||
203 | |||
204 | extern int tda18271_assign_map_layout(struct dvb_frontend *fe); | ||
205 | |||
206 | /*---------------------------------------------------------------------*/ | ||
207 | |||
208 | extern int tda18271_read_regs(struct dvb_frontend *fe); | ||
209 | extern int tda18271_read_extended(struct dvb_frontend *fe); | ||
210 | extern int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len); | ||
211 | extern int tda18271_init_regs(struct dvb_frontend *fe); | ||
212 | |||
213 | extern int tda18271_charge_pump_source(struct dvb_frontend *fe, | ||
214 | enum tda18271_pll pll, int force); | ||
215 | extern int tda18271_set_standby_mode(struct dvb_frontend *fe, | ||
216 | int sm, int sm_lt, int sm_xt); | ||
217 | |||
218 | extern int tda18271_calc_main_pll(struct dvb_frontend *fe, u32 freq); | ||
219 | extern int tda18271_calc_cal_pll(struct dvb_frontend *fe, u32 freq); | ||
220 | |||
221 | extern int tda18271_calc_bp_filter(struct dvb_frontend *fe, u32 *freq); | ||
222 | extern int tda18271_calc_km(struct dvb_frontend *fe, u32 *freq); | ||
223 | extern int tda18271_calc_rf_band(struct dvb_frontend *fe, u32 *freq); | ||
224 | extern int tda18271_calc_gain_taper(struct dvb_frontend *fe, u32 *freq); | ||
225 | extern int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq); | ||
226 | extern int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq); | ||
227 | |||
228 | #endif /* __TDA18271_PRIV_H__ */ | ||
229 | |||
230 | /* | ||
231 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
232 | * --------------------------------------------------------------------------- | ||
233 | * Local variables: | ||
234 | * c-basic-offset: 8 | ||
235 | * End: | ||
236 | */ | ||
diff --git a/drivers/media/tuners/tda18271.h b/drivers/media/tuners/tda18271.h new file mode 100644 index 000000000000..640bae4e6a5a --- /dev/null +++ b/drivers/media/tuners/tda18271.h | |||
@@ -0,0 +1,134 @@ | |||
1 | /* | ||
2 | tda18271.h - header for the Philips / NXP TDA18271 silicon tuner | ||
3 | |||
4 | Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org> | ||
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 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef __TDA18271_H__ | ||
22 | #define __TDA18271_H__ | ||
23 | |||
24 | #include <linux/i2c.h> | ||
25 | #include "dvb_frontend.h" | ||
26 | |||
27 | struct tda18271_std_map_item { | ||
28 | u16 if_freq; | ||
29 | |||
30 | /* EP3[4:3] */ | ||
31 | unsigned int agc_mode:2; | ||
32 | /* EP3[2:0] */ | ||
33 | unsigned int std:3; | ||
34 | /* EP4[7] */ | ||
35 | unsigned int fm_rfn:1; | ||
36 | /* EP4[4:2] */ | ||
37 | unsigned int if_lvl:3; | ||
38 | /* EB22[6:0] */ | ||
39 | unsigned int rfagc_top:7; | ||
40 | }; | ||
41 | |||
42 | struct tda18271_std_map { | ||
43 | struct tda18271_std_map_item fm_radio; | ||
44 | struct tda18271_std_map_item atv_b; | ||
45 | struct tda18271_std_map_item atv_dk; | ||
46 | struct tda18271_std_map_item atv_gh; | ||
47 | struct tda18271_std_map_item atv_i; | ||
48 | struct tda18271_std_map_item atv_l; | ||
49 | struct tda18271_std_map_item atv_lc; | ||
50 | struct tda18271_std_map_item atv_mn; | ||
51 | struct tda18271_std_map_item atsc_6; | ||
52 | struct tda18271_std_map_item dvbt_6; | ||
53 | struct tda18271_std_map_item dvbt_7; | ||
54 | struct tda18271_std_map_item dvbt_8; | ||
55 | struct tda18271_std_map_item qam_6; | ||
56 | struct tda18271_std_map_item qam_7; | ||
57 | struct tda18271_std_map_item qam_8; | ||
58 | }; | ||
59 | |||
60 | enum tda18271_role { | ||
61 | TDA18271_MASTER = 0, | ||
62 | TDA18271_SLAVE, | ||
63 | }; | ||
64 | |||
65 | enum tda18271_i2c_gate { | ||
66 | TDA18271_GATE_AUTO = 0, | ||
67 | TDA18271_GATE_ANALOG, | ||
68 | TDA18271_GATE_DIGITAL, | ||
69 | }; | ||
70 | |||
71 | enum tda18271_output_options { | ||
72 | /* slave tuner output & loop thru & xtal oscillator always on */ | ||
73 | TDA18271_OUTPUT_LT_XT_ON = 0, | ||
74 | |||
75 | /* slave tuner output loop thru off */ | ||
76 | TDA18271_OUTPUT_LT_OFF = 1, | ||
77 | |||
78 | /* xtal oscillator off */ | ||
79 | TDA18271_OUTPUT_XT_OFF = 2, | ||
80 | }; | ||
81 | |||
82 | enum tda18271_small_i2c { | ||
83 | TDA18271_39_BYTE_CHUNK_INIT = 0, | ||
84 | TDA18271_16_BYTE_CHUNK_INIT = 16, | ||
85 | TDA18271_08_BYTE_CHUNK_INIT = 8, | ||
86 | TDA18271_03_BYTE_CHUNK_INIT = 3, | ||
87 | }; | ||
88 | |||
89 | struct tda18271_config { | ||
90 | /* override default if freq / std settings (optional) */ | ||
91 | struct tda18271_std_map *std_map; | ||
92 | |||
93 | /* master / slave tuner: master uses main pll, slave uses cal pll */ | ||
94 | enum tda18271_role role; | ||
95 | |||
96 | /* use i2c gate provided by analog or digital demod */ | ||
97 | enum tda18271_i2c_gate gate; | ||
98 | |||
99 | /* output options that can be disabled */ | ||
100 | enum tda18271_output_options output_opt; | ||
101 | |||
102 | /* some i2c providers can't write all 39 registers at once */ | ||
103 | enum tda18271_small_i2c small_i2c; | ||
104 | |||
105 | /* force rf tracking filter calibration on startup */ | ||
106 | unsigned int rf_cal_on_startup:1; | ||
107 | |||
108 | /* interface to saa713x / tda829x */ | ||
109 | unsigned int config; | ||
110 | }; | ||
111 | |||
112 | #define TDA18271_CALLBACK_CMD_AGC_ENABLE 0 | ||
113 | |||
114 | enum tda18271_mode { | ||
115 | TDA18271_ANALOG = 0, | ||
116 | TDA18271_DIGITAL, | ||
117 | }; | ||
118 | |||
119 | #if defined(CONFIG_MEDIA_TUNER_TDA18271) || (defined(CONFIG_MEDIA_TUNER_TDA18271_MODULE) && defined(MODULE)) | ||
120 | extern struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr, | ||
121 | struct i2c_adapter *i2c, | ||
122 | struct tda18271_config *cfg); | ||
123 | #else | ||
124 | static inline struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, | ||
125 | u8 addr, | ||
126 | struct i2c_adapter *i2c, | ||
127 | struct tda18271_config *cfg) | ||
128 | { | ||
129 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
130 | return NULL; | ||
131 | } | ||
132 | #endif | ||
133 | |||
134 | #endif /* __TDA18271_H__ */ | ||
diff --git a/drivers/media/tuners/tda827x.c b/drivers/media/tuners/tda827x.c new file mode 100644 index 000000000000..a0d176267470 --- /dev/null +++ b/drivers/media/tuners/tda827x.c | |||
@@ -0,0 +1,917 @@ | |||
1 | /* | ||
2 | * | ||
3 | * (c) 2005 Hartmut Hackmann | ||
4 | * (c) 2007 Michael Krufky | ||
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 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <asm/types.h> | ||
24 | #include <linux/dvb/frontend.h> | ||
25 | #include <linux/videodev2.h> | ||
26 | |||
27 | #include "tda827x.h" | ||
28 | |||
29 | static int debug; | ||
30 | module_param(debug, int, 0644); | ||
31 | MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); | ||
32 | |||
33 | #define dprintk(args...) \ | ||
34 | do { \ | ||
35 | if (debug) printk(KERN_DEBUG "tda827x: " args); \ | ||
36 | } while (0) | ||
37 | |||
38 | struct tda827x_priv { | ||
39 | int i2c_addr; | ||
40 | struct i2c_adapter *i2c_adap; | ||
41 | struct tda827x_config *cfg; | ||
42 | |||
43 | unsigned int sgIF; | ||
44 | unsigned char lpsel; | ||
45 | |||
46 | u32 frequency; | ||
47 | u32 bandwidth; | ||
48 | }; | ||
49 | |||
50 | static void tda827x_set_std(struct dvb_frontend *fe, | ||
51 | struct analog_parameters *params) | ||
52 | { | ||
53 | struct tda827x_priv *priv = fe->tuner_priv; | ||
54 | char *mode; | ||
55 | |||
56 | priv->lpsel = 0; | ||
57 | if (params->std & V4L2_STD_MN) { | ||
58 | priv->sgIF = 92; | ||
59 | priv->lpsel = 1; | ||
60 | mode = "MN"; | ||
61 | } else if (params->std & V4L2_STD_B) { | ||
62 | priv->sgIF = 108; | ||
63 | mode = "B"; | ||
64 | } else if (params->std & V4L2_STD_GH) { | ||
65 | priv->sgIF = 124; | ||
66 | mode = "GH"; | ||
67 | } else if (params->std & V4L2_STD_PAL_I) { | ||
68 | priv->sgIF = 124; | ||
69 | mode = "I"; | ||
70 | } else if (params->std & V4L2_STD_DK) { | ||
71 | priv->sgIF = 124; | ||
72 | mode = "DK"; | ||
73 | } else if (params->std & V4L2_STD_SECAM_L) { | ||
74 | priv->sgIF = 124; | ||
75 | mode = "L"; | ||
76 | } else if (params->std & V4L2_STD_SECAM_LC) { | ||
77 | priv->sgIF = 20; | ||
78 | mode = "LC"; | ||
79 | } else { | ||
80 | priv->sgIF = 124; | ||
81 | mode = "xx"; | ||
82 | } | ||
83 | |||
84 | if (params->mode == V4L2_TUNER_RADIO) { | ||
85 | priv->sgIF = 88; /* if frequency is 5.5 MHz */ | ||
86 | dprintk("setting tda827x to radio FM\n"); | ||
87 | } else | ||
88 | dprintk("setting tda827x to system %s\n", mode); | ||
89 | } | ||
90 | |||
91 | |||
92 | /* ------------------------------------------------------------------ */ | ||
93 | |||
94 | struct tda827x_data { | ||
95 | u32 lomax; | ||
96 | u8 spd; | ||
97 | u8 bs; | ||
98 | u8 bp; | ||
99 | u8 cp; | ||
100 | u8 gc3; | ||
101 | u8 div1p5; | ||
102 | }; | ||
103 | |||
104 | static const struct tda827x_data tda827x_table[] = { | ||
105 | { .lomax = 62000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, | ||
106 | { .lomax = 66000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1}, | ||
107 | { .lomax = 76000000, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, | ||
108 | { .lomax = 84000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0}, | ||
109 | { .lomax = 93000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
110 | { .lomax = 98000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
111 | { .lomax = 109000000, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
112 | { .lomax = 123000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, | ||
113 | { .lomax = 133000000, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1}, | ||
114 | { .lomax = 151000000, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
115 | { .lomax = 154000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
116 | { .lomax = 181000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0}, | ||
117 | { .lomax = 185000000, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
118 | { .lomax = 217000000, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
119 | { .lomax = 244000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, | ||
120 | { .lomax = 265000000, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1}, | ||
121 | { .lomax = 302000000, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
122 | { .lomax = 324000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
123 | { .lomax = 370000000, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
124 | { .lomax = 454000000, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
125 | { .lomax = 493000000, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, | ||
126 | { .lomax = 530000000, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1}, | ||
127 | { .lomax = 554000000, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0}, | ||
128 | { .lomax = 604000000, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, | ||
129 | { .lomax = 696000000, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, | ||
130 | { .lomax = 740000000, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, | ||
131 | { .lomax = 820000000, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0}, | ||
132 | { .lomax = 865000000, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0}, | ||
133 | { .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0} | ||
134 | }; | ||
135 | |||
136 | static int tuner_transfer(struct dvb_frontend *fe, | ||
137 | struct i2c_msg *msg, | ||
138 | const int size) | ||
139 | { | ||
140 | int rc; | ||
141 | struct tda827x_priv *priv = fe->tuner_priv; | ||
142 | |||
143 | if (fe->ops.i2c_gate_ctrl) | ||
144 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
145 | rc = i2c_transfer(priv->i2c_adap, msg, size); | ||
146 | if (fe->ops.i2c_gate_ctrl) | ||
147 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
148 | |||
149 | if (rc >= 0 && rc != size) | ||
150 | return -EIO; | ||
151 | |||
152 | return rc; | ||
153 | } | ||
154 | |||
155 | static int tda827xo_set_params(struct dvb_frontend *fe) | ||
156 | { | ||
157 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
158 | struct tda827x_priv *priv = fe->tuner_priv; | ||
159 | u8 buf[14]; | ||
160 | int rc; | ||
161 | |||
162 | struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, | ||
163 | .buf = buf, .len = sizeof(buf) }; | ||
164 | int i, tuner_freq, if_freq; | ||
165 | u32 N; | ||
166 | |||
167 | dprintk("%s:\n", __func__); | ||
168 | if (c->bandwidth_hz == 0) { | ||
169 | if_freq = 5000000; | ||
170 | } else if (c->bandwidth_hz <= 6000000) { | ||
171 | if_freq = 4000000; | ||
172 | } else if (c->bandwidth_hz <= 7000000) { | ||
173 | if_freq = 4500000; | ||
174 | } else { /* 8 MHz */ | ||
175 | if_freq = 5000000; | ||
176 | } | ||
177 | tuner_freq = c->frequency; | ||
178 | |||
179 | i = 0; | ||
180 | while (tda827x_table[i].lomax < tuner_freq) { | ||
181 | if (tda827x_table[i + 1].lomax == 0) | ||
182 | break; | ||
183 | i++; | ||
184 | } | ||
185 | |||
186 | tuner_freq += if_freq; | ||
187 | |||
188 | N = ((tuner_freq + 125000) / 250000) << (tda827x_table[i].spd + 2); | ||
189 | buf[0] = 0; | ||
190 | buf[1] = (N>>8) | 0x40; | ||
191 | buf[2] = N & 0xff; | ||
192 | buf[3] = 0; | ||
193 | buf[4] = 0x52; | ||
194 | buf[5] = (tda827x_table[i].spd << 6) + (tda827x_table[i].div1p5 << 5) + | ||
195 | (tda827x_table[i].bs << 3) + | ||
196 | tda827x_table[i].bp; | ||
197 | buf[6] = (tda827x_table[i].gc3 << 4) + 0x8f; | ||
198 | buf[7] = 0xbf; | ||
199 | buf[8] = 0x2a; | ||
200 | buf[9] = 0x05; | ||
201 | buf[10] = 0xff; | ||
202 | buf[11] = 0x00; | ||
203 | buf[12] = 0x00; | ||
204 | buf[13] = 0x40; | ||
205 | |||
206 | msg.len = 14; | ||
207 | rc = tuner_transfer(fe, &msg, 1); | ||
208 | if (rc < 0) | ||
209 | goto err; | ||
210 | |||
211 | msleep(500); | ||
212 | /* correct CP value */ | ||
213 | buf[0] = 0x30; | ||
214 | buf[1] = 0x50 + tda827x_table[i].cp; | ||
215 | msg.len = 2; | ||
216 | |||
217 | rc = tuner_transfer(fe, &msg, 1); | ||
218 | if (rc < 0) | ||
219 | goto err; | ||
220 | |||
221 | priv->frequency = c->frequency; | ||
222 | priv->bandwidth = c->bandwidth_hz; | ||
223 | |||
224 | return 0; | ||
225 | |||
226 | err: | ||
227 | printk(KERN_ERR "%s: could not write to tuner at addr: 0x%02x\n", | ||
228 | __func__, priv->i2c_addr << 1); | ||
229 | return rc; | ||
230 | } | ||
231 | |||
232 | static int tda827xo_sleep(struct dvb_frontend *fe) | ||
233 | { | ||
234 | struct tda827x_priv *priv = fe->tuner_priv; | ||
235 | static u8 buf[] = { 0x30, 0xd0 }; | ||
236 | struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, | ||
237 | .buf = buf, .len = sizeof(buf) }; | ||
238 | |||
239 | dprintk("%s:\n", __func__); | ||
240 | tuner_transfer(fe, &msg, 1); | ||
241 | |||
242 | if (priv->cfg && priv->cfg->sleep) | ||
243 | priv->cfg->sleep(fe); | ||
244 | |||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | /* ------------------------------------------------------------------ */ | ||
249 | |||
250 | static int tda827xo_set_analog_params(struct dvb_frontend *fe, | ||
251 | struct analog_parameters *params) | ||
252 | { | ||
253 | unsigned char tuner_reg[8]; | ||
254 | unsigned char reg2[2]; | ||
255 | u32 N; | ||
256 | int i; | ||
257 | struct tda827x_priv *priv = fe->tuner_priv; | ||
258 | struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0 }; | ||
259 | unsigned int freq = params->frequency; | ||
260 | |||
261 | tda827x_set_std(fe, params); | ||
262 | |||
263 | if (params->mode == V4L2_TUNER_RADIO) | ||
264 | freq = freq / 1000; | ||
265 | |||
266 | N = freq + priv->sgIF; | ||
267 | |||
268 | i = 0; | ||
269 | while (tda827x_table[i].lomax < N * 62500) { | ||
270 | if (tda827x_table[i + 1].lomax == 0) | ||
271 | break; | ||
272 | i++; | ||
273 | } | ||
274 | |||
275 | N = N << tda827x_table[i].spd; | ||
276 | |||
277 | tuner_reg[0] = 0; | ||
278 | tuner_reg[1] = (unsigned char)(N>>8); | ||
279 | tuner_reg[2] = (unsigned char) N; | ||
280 | tuner_reg[3] = 0x40; | ||
281 | tuner_reg[4] = 0x52 + (priv->lpsel << 5); | ||
282 | tuner_reg[5] = (tda827x_table[i].spd << 6) + | ||
283 | (tda827x_table[i].div1p5 << 5) + | ||
284 | (tda827x_table[i].bs << 3) + tda827x_table[i].bp; | ||
285 | tuner_reg[6] = 0x8f + (tda827x_table[i].gc3 << 4); | ||
286 | tuner_reg[7] = 0x8f; | ||
287 | |||
288 | msg.buf = tuner_reg; | ||
289 | msg.len = 8; | ||
290 | tuner_transfer(fe, &msg, 1); | ||
291 | |||
292 | msg.buf = reg2; | ||
293 | msg.len = 2; | ||
294 | reg2[0] = 0x80; | ||
295 | reg2[1] = 0; | ||
296 | tuner_transfer(fe, &msg, 1); | ||
297 | |||
298 | reg2[0] = 0x60; | ||
299 | reg2[1] = 0xbf; | ||
300 | tuner_transfer(fe, &msg, 1); | ||
301 | |||
302 | reg2[0] = 0x30; | ||
303 | reg2[1] = tuner_reg[4] + 0x80; | ||
304 | tuner_transfer(fe, &msg, 1); | ||
305 | |||
306 | msleep(1); | ||
307 | reg2[0] = 0x30; | ||
308 | reg2[1] = tuner_reg[4] + 4; | ||
309 | tuner_transfer(fe, &msg, 1); | ||
310 | |||
311 | msleep(1); | ||
312 | reg2[0] = 0x30; | ||
313 | reg2[1] = tuner_reg[4]; | ||
314 | tuner_transfer(fe, &msg, 1); | ||
315 | |||
316 | msleep(550); | ||
317 | reg2[0] = 0x30; | ||
318 | reg2[1] = (tuner_reg[4] & 0xfc) + tda827x_table[i].cp; | ||
319 | tuner_transfer(fe, &msg, 1); | ||
320 | |||
321 | reg2[0] = 0x60; | ||
322 | reg2[1] = 0x3f; | ||
323 | tuner_transfer(fe, &msg, 1); | ||
324 | |||
325 | reg2[0] = 0x80; | ||
326 | reg2[1] = 0x08; /* Vsync en */ | ||
327 | tuner_transfer(fe, &msg, 1); | ||
328 | |||
329 | priv->frequency = params->frequency; | ||
330 | |||
331 | return 0; | ||
332 | } | ||
333 | |||
334 | static void tda827xo_agcf(struct dvb_frontend *fe) | ||
335 | { | ||
336 | struct tda827x_priv *priv = fe->tuner_priv; | ||
337 | unsigned char data[] = { 0x80, 0x0c }; | ||
338 | struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, | ||
339 | .buf = data, .len = 2}; | ||
340 | |||
341 | tuner_transfer(fe, &msg, 1); | ||
342 | } | ||
343 | |||
344 | /* ------------------------------------------------------------------ */ | ||
345 | |||
346 | struct tda827xa_data { | ||
347 | u32 lomax; | ||
348 | u8 svco; | ||
349 | u8 spd; | ||
350 | u8 scr; | ||
351 | u8 sbs; | ||
352 | u8 gc3; | ||
353 | }; | ||
354 | |||
355 | static struct tda827xa_data tda827xa_dvbt[] = { | ||
356 | { .lomax = 56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 1}, | ||
357 | { .lomax = 67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, | ||
358 | { .lomax = 81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, | ||
359 | { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 1}, | ||
360 | { .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1}, | ||
361 | { .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, | ||
362 | { .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, | ||
363 | { .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, | ||
364 | { .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, | ||
365 | { .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, | ||
366 | { .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, | ||
367 | { .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, | ||
368 | { .lomax = 290000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, | ||
369 | { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, | ||
370 | { .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, | ||
371 | { .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 1}, | ||
372 | { .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, | ||
373 | { .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, | ||
374 | { .lomax = 550000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, | ||
375 | { .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, | ||
376 | { .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, | ||
377 | { .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, | ||
378 | { .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, | ||
379 | { .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, | ||
380 | { .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, | ||
381 | { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0}, | ||
382 | { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} | ||
383 | }; | ||
384 | |||
385 | static struct tda827xa_data tda827xa_dvbc[] = { | ||
386 | { .lomax = 50125000, .svco = 2, .spd = 4, .scr = 2, .sbs = 0, .gc3 = 3}, | ||
387 | { .lomax = 58500000, .svco = 3, .spd = 4, .scr = 2, .sbs = 0, .gc3 = 3}, | ||
388 | { .lomax = 69250000, .svco = 0, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3}, | ||
389 | { .lomax = 83625000, .svco = 1, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3}, | ||
390 | { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 2, .sbs = 0, .gc3 = 3}, | ||
391 | { .lomax = 100250000, .svco = 2, .spd = 3, .scr = 2, .sbs = 1, .gc3 = 1}, | ||
392 | { .lomax = 117000000, .svco = 3, .spd = 3, .scr = 2, .sbs = 1, .gc3 = 1}, | ||
393 | { .lomax = 138500000, .svco = 0, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1}, | ||
394 | { .lomax = 167250000, .svco = 1, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1}, | ||
395 | { .lomax = 187000000, .svco = 2, .spd = 2, .scr = 2, .sbs = 1, .gc3 = 1}, | ||
396 | { .lomax = 200500000, .svco = 2, .spd = 2, .scr = 2, .sbs = 2, .gc3 = 1}, | ||
397 | { .lomax = 234000000, .svco = 3, .spd = 2, .scr = 2, .sbs = 2, .gc3 = 3}, | ||
398 | { .lomax = 277000000, .svco = 0, .spd = 1, .scr = 2, .sbs = 2, .gc3 = 3}, | ||
399 | { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 2, .sbs = 2, .gc3 = 1}, | ||
400 | { .lomax = 334500000, .svco = 1, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 3}, | ||
401 | { .lomax = 401000000, .svco = 2, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 3}, | ||
402 | { .lomax = 468000000, .svco = 3, .spd = 1, .scr = 2, .sbs = 3, .gc3 = 1}, | ||
403 | { .lomax = 535000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, | ||
404 | { .lomax = 554000000, .svco = 0, .spd = 0, .scr = 2, .sbs = 3, .gc3 = 1}, | ||
405 | { .lomax = 638000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1}, | ||
406 | { .lomax = 669000000, .svco = 1, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1}, | ||
407 | { .lomax = 720000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1}, | ||
408 | { .lomax = 802000000, .svco = 2, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1}, | ||
409 | { .lomax = 835000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1}, | ||
410 | { .lomax = 885000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 1}, | ||
411 | { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 1}, | ||
412 | { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} | ||
413 | }; | ||
414 | |||
415 | static struct tda827xa_data tda827xa_analog[] = { | ||
416 | { .lomax = 56875000, .svco = 3, .spd = 4, .scr = 0, .sbs = 0, .gc3 = 3}, | ||
417 | { .lomax = 67250000, .svco = 0, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, | ||
418 | { .lomax = 81250000, .svco = 1, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, | ||
419 | { .lomax = 97500000, .svco = 2, .spd = 3, .scr = 0, .sbs = 0, .gc3 = 3}, | ||
420 | { .lomax = 113750000, .svco = 3, .spd = 3, .scr = 0, .sbs = 1, .gc3 = 1}, | ||
421 | { .lomax = 134500000, .svco = 0, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, | ||
422 | { .lomax = 154000000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, | ||
423 | { .lomax = 162500000, .svco = 1, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, | ||
424 | { .lomax = 183000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 1, .gc3 = 1}, | ||
425 | { .lomax = 195000000, .svco = 2, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 1}, | ||
426 | { .lomax = 227500000, .svco = 3, .spd = 2, .scr = 0, .sbs = 2, .gc3 = 3}, | ||
427 | { .lomax = 269000000, .svco = 0, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 3}, | ||
428 | { .lomax = 325000000, .svco = 1, .spd = 1, .scr = 0, .sbs = 2, .gc3 = 1}, | ||
429 | { .lomax = 390000000, .svco = 2, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3}, | ||
430 | { .lomax = 455000000, .svco = 3, .spd = 1, .scr = 0, .sbs = 3, .gc3 = 3}, | ||
431 | { .lomax = 520000000, .svco = 0, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, | ||
432 | { .lomax = 538000000, .svco = 0, .spd = 0, .scr = 1, .sbs = 3, .gc3 = 1}, | ||
433 | { .lomax = 554000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 3, .gc3 = 1}, | ||
434 | { .lomax = 620000000, .svco = 1, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, | ||
435 | { .lomax = 650000000, .svco = 1, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, | ||
436 | { .lomax = 700000000, .svco = 2, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, | ||
437 | { .lomax = 780000000, .svco = 2, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, | ||
438 | { .lomax = 820000000, .svco = 3, .spd = 0, .scr = 0, .sbs = 4, .gc3 = 0}, | ||
439 | { .lomax = 870000000, .svco = 3, .spd = 0, .scr = 1, .sbs = 4, .gc3 = 0}, | ||
440 | { .lomax = 911000000, .svco = 3, .spd = 0, .scr = 2, .sbs = 4, .gc3 = 0}, | ||
441 | { .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0} | ||
442 | }; | ||
443 | |||
444 | static int tda827xa_sleep(struct dvb_frontend *fe) | ||
445 | { | ||
446 | struct tda827x_priv *priv = fe->tuner_priv; | ||
447 | static u8 buf[] = { 0x30, 0x90 }; | ||
448 | struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, | ||
449 | .buf = buf, .len = sizeof(buf) }; | ||
450 | |||
451 | dprintk("%s:\n", __func__); | ||
452 | |||
453 | tuner_transfer(fe, &msg, 1); | ||
454 | |||
455 | if (priv->cfg && priv->cfg->sleep) | ||
456 | priv->cfg->sleep(fe); | ||
457 | |||
458 | return 0; | ||
459 | } | ||
460 | |||
461 | static void tda827xa_lna_gain(struct dvb_frontend *fe, int high, | ||
462 | struct analog_parameters *params) | ||
463 | { | ||
464 | struct tda827x_priv *priv = fe->tuner_priv; | ||
465 | unsigned char buf[] = {0x22, 0x01}; | ||
466 | int arg; | ||
467 | int gp_func; | ||
468 | struct i2c_msg msg = { .flags = 0, .buf = buf, .len = sizeof(buf) }; | ||
469 | |||
470 | if (NULL == priv->cfg) { | ||
471 | dprintk("tda827x_config not defined, cannot set LNA gain!\n"); | ||
472 | return; | ||
473 | } | ||
474 | msg.addr = priv->cfg->switch_addr; | ||
475 | if (priv->cfg->config) { | ||
476 | if (high) | ||
477 | dprintk("setting LNA to high gain\n"); | ||
478 | else | ||
479 | dprintk("setting LNA to low gain\n"); | ||
480 | } | ||
481 | switch (priv->cfg->config) { | ||
482 | case 0: /* no LNA */ | ||
483 | break; | ||
484 | case 1: /* switch is GPIO 0 of tda8290 */ | ||
485 | case 2: | ||
486 | if (params == NULL) { | ||
487 | gp_func = 0; | ||
488 | arg = 0; | ||
489 | } else { | ||
490 | /* turn Vsync on */ | ||
491 | gp_func = 1; | ||
492 | if (params->std & V4L2_STD_MN) | ||
493 | arg = 1; | ||
494 | else | ||
495 | arg = 0; | ||
496 | } | ||
497 | if (fe->callback) | ||
498 | fe->callback(priv->i2c_adap->algo_data, | ||
499 | DVB_FRONTEND_COMPONENT_TUNER, | ||
500 | gp_func, arg); | ||
501 | buf[1] = high ? 0 : 1; | ||
502 | if (priv->cfg->config == 2) | ||
503 | buf[1] = high ? 1 : 0; | ||
504 | tuner_transfer(fe, &msg, 1); | ||
505 | break; | ||
506 | case 3: /* switch with GPIO of saa713x */ | ||
507 | if (fe->callback) | ||
508 | fe->callback(priv->i2c_adap->algo_data, | ||
509 | DVB_FRONTEND_COMPONENT_TUNER, 0, high); | ||
510 | break; | ||
511 | } | ||
512 | } | ||
513 | |||
514 | static int tda827xa_set_params(struct dvb_frontend *fe) | ||
515 | { | ||
516 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
517 | struct tda827x_priv *priv = fe->tuner_priv; | ||
518 | struct tda827xa_data *frequency_map = tda827xa_dvbt; | ||
519 | u8 buf[11]; | ||
520 | |||
521 | struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, | ||
522 | .buf = buf, .len = sizeof(buf) }; | ||
523 | |||
524 | int i, tuner_freq, if_freq, rc; | ||
525 | u32 N; | ||
526 | |||
527 | dprintk("%s:\n", __func__); | ||
528 | |||
529 | tda827xa_lna_gain(fe, 1, NULL); | ||
530 | msleep(20); | ||
531 | |||
532 | if (c->bandwidth_hz == 0) { | ||
533 | if_freq = 5000000; | ||
534 | } else if (c->bandwidth_hz <= 6000000) { | ||
535 | if_freq = 4000000; | ||
536 | } else if (c->bandwidth_hz <= 7000000) { | ||
537 | if_freq = 4500000; | ||
538 | } else { /* 8 MHz */ | ||
539 | if_freq = 5000000; | ||
540 | } | ||
541 | tuner_freq = c->frequency; | ||
542 | |||
543 | switch (c->delivery_system) { | ||
544 | case SYS_DVBC_ANNEX_A: | ||
545 | case SYS_DVBC_ANNEX_C: | ||
546 | dprintk("%s select tda827xa_dvbc\n", __func__); | ||
547 | frequency_map = tda827xa_dvbc; | ||
548 | break; | ||
549 | default: | ||
550 | break; | ||
551 | } | ||
552 | |||
553 | i = 0; | ||
554 | while (frequency_map[i].lomax < tuner_freq) { | ||
555 | if (frequency_map[i + 1].lomax == 0) | ||
556 | break; | ||
557 | i++; | ||
558 | } | ||
559 | |||
560 | tuner_freq += if_freq; | ||
561 | |||
562 | N = ((tuner_freq + 31250) / 62500) << frequency_map[i].spd; | ||
563 | buf[0] = 0; // subaddress | ||
564 | buf[1] = N >> 8; | ||
565 | buf[2] = N & 0xff; | ||
566 | buf[3] = 0; | ||
567 | buf[4] = 0x16; | ||
568 | buf[5] = (frequency_map[i].spd << 5) + (frequency_map[i].svco << 3) + | ||
569 | frequency_map[i].sbs; | ||
570 | buf[6] = 0x4b + (frequency_map[i].gc3 << 4); | ||
571 | buf[7] = 0x1c; | ||
572 | buf[8] = 0x06; | ||
573 | buf[9] = 0x24; | ||
574 | buf[10] = 0x00; | ||
575 | msg.len = 11; | ||
576 | rc = tuner_transfer(fe, &msg, 1); | ||
577 | if (rc < 0) | ||
578 | goto err; | ||
579 | |||
580 | buf[0] = 0x90; | ||
581 | buf[1] = 0xff; | ||
582 | buf[2] = 0x60; | ||
583 | buf[3] = 0x00; | ||
584 | buf[4] = 0x59; // lpsel, for 6MHz + 2 | ||
585 | msg.len = 5; | ||
586 | rc = tuner_transfer(fe, &msg, 1); | ||
587 | if (rc < 0) | ||
588 | goto err; | ||
589 | |||
590 | buf[0] = 0xa0; | ||
591 | buf[1] = 0x40; | ||
592 | msg.len = 2; | ||
593 | rc = tuner_transfer(fe, &msg, 1); | ||
594 | if (rc < 0) | ||
595 | goto err; | ||
596 | |||
597 | msleep(11); | ||
598 | msg.flags = I2C_M_RD; | ||
599 | rc = tuner_transfer(fe, &msg, 1); | ||
600 | if (rc < 0) | ||
601 | goto err; | ||
602 | msg.flags = 0; | ||
603 | |||
604 | buf[1] >>= 4; | ||
605 | dprintk("tda8275a AGC2 gain is: %d\n", buf[1]); | ||
606 | if ((buf[1]) < 2) { | ||
607 | tda827xa_lna_gain(fe, 0, NULL); | ||
608 | buf[0] = 0x60; | ||
609 | buf[1] = 0x0c; | ||
610 | rc = tuner_transfer(fe, &msg, 1); | ||
611 | if (rc < 0) | ||
612 | goto err; | ||
613 | } | ||
614 | |||
615 | buf[0] = 0xc0; | ||
616 | buf[1] = 0x99; // lpsel, for 6MHz + 2 | ||
617 | rc = tuner_transfer(fe, &msg, 1); | ||
618 | if (rc < 0) | ||
619 | goto err; | ||
620 | |||
621 | buf[0] = 0x60; | ||
622 | buf[1] = 0x3c; | ||
623 | rc = tuner_transfer(fe, &msg, 1); | ||
624 | if (rc < 0) | ||
625 | goto err; | ||
626 | |||
627 | /* correct CP value */ | ||
628 | buf[0] = 0x30; | ||
629 | buf[1] = 0x10 + frequency_map[i].scr; | ||
630 | rc = tuner_transfer(fe, &msg, 1); | ||
631 | if (rc < 0) | ||
632 | goto err; | ||
633 | |||
634 | msleep(163); | ||
635 | buf[0] = 0xc0; | ||
636 | buf[1] = 0x39; // lpsel, for 6MHz + 2 | ||
637 | rc = tuner_transfer(fe, &msg, 1); | ||
638 | if (rc < 0) | ||
639 | goto err; | ||
640 | |||
641 | msleep(3); | ||
642 | /* freeze AGC1 */ | ||
643 | buf[0] = 0x50; | ||
644 | buf[1] = 0x4f + (frequency_map[i].gc3 << 4); | ||
645 | rc = tuner_transfer(fe, &msg, 1); | ||
646 | if (rc < 0) | ||
647 | goto err; | ||
648 | |||
649 | priv->frequency = c->frequency; | ||
650 | priv->bandwidth = c->bandwidth_hz; | ||
651 | |||
652 | return 0; | ||
653 | |||
654 | err: | ||
655 | printk(KERN_ERR "%s: could not write to tuner at addr: 0x%02x\n", | ||
656 | __func__, priv->i2c_addr << 1); | ||
657 | return rc; | ||
658 | } | ||
659 | |||
660 | |||
661 | static int tda827xa_set_analog_params(struct dvb_frontend *fe, | ||
662 | struct analog_parameters *params) | ||
663 | { | ||
664 | unsigned char tuner_reg[11]; | ||
665 | u32 N; | ||
666 | int i; | ||
667 | struct tda827x_priv *priv = fe->tuner_priv; | ||
668 | struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0, | ||
669 | .buf = tuner_reg, .len = sizeof(tuner_reg) }; | ||
670 | unsigned int freq = params->frequency; | ||
671 | |||
672 | tda827x_set_std(fe, params); | ||
673 | |||
674 | tda827xa_lna_gain(fe, 1, params); | ||
675 | msleep(10); | ||
676 | |||
677 | if (params->mode == V4L2_TUNER_RADIO) | ||
678 | freq = freq / 1000; | ||
679 | |||
680 | N = freq + priv->sgIF; | ||
681 | |||
682 | i = 0; | ||
683 | while (tda827xa_analog[i].lomax < N * 62500) { | ||
684 | if (tda827xa_analog[i + 1].lomax == 0) | ||
685 | break; | ||
686 | i++; | ||
687 | } | ||
688 | |||
689 | N = N << tda827xa_analog[i].spd; | ||
690 | |||
691 | tuner_reg[0] = 0; | ||
692 | tuner_reg[1] = (unsigned char)(N>>8); | ||
693 | tuner_reg[2] = (unsigned char) N; | ||
694 | tuner_reg[3] = 0; | ||
695 | tuner_reg[4] = 0x16; | ||
696 | tuner_reg[5] = (tda827xa_analog[i].spd << 5) + | ||
697 | (tda827xa_analog[i].svco << 3) + | ||
698 | tda827xa_analog[i].sbs; | ||
699 | tuner_reg[6] = 0x8b + (tda827xa_analog[i].gc3 << 4); | ||
700 | tuner_reg[7] = 0x1c; | ||
701 | tuner_reg[8] = 4; | ||
702 | tuner_reg[9] = 0x20; | ||
703 | tuner_reg[10] = 0x00; | ||
704 | msg.len = 11; | ||
705 | tuner_transfer(fe, &msg, 1); | ||
706 | |||
707 | tuner_reg[0] = 0x90; | ||
708 | tuner_reg[1] = 0xff; | ||
709 | tuner_reg[2] = 0xe0; | ||
710 | tuner_reg[3] = 0; | ||
711 | tuner_reg[4] = 0x99 + (priv->lpsel << 1); | ||
712 | msg.len = 5; | ||
713 | tuner_transfer(fe, &msg, 1); | ||
714 | |||
715 | tuner_reg[0] = 0xa0; | ||
716 | tuner_reg[1] = 0xc0; | ||
717 | msg.len = 2; | ||
718 | tuner_transfer(fe, &msg, 1); | ||
719 | |||
720 | tuner_reg[0] = 0x30; | ||
721 | tuner_reg[1] = 0x10 + tda827xa_analog[i].scr; | ||
722 | tuner_transfer(fe, &msg, 1); | ||
723 | |||
724 | msg.flags = I2C_M_RD; | ||
725 | tuner_transfer(fe, &msg, 1); | ||
726 | msg.flags = 0; | ||
727 | tuner_reg[1] >>= 4; | ||
728 | dprintk("AGC2 gain is: %d\n", tuner_reg[1]); | ||
729 | if (tuner_reg[1] < 1) | ||
730 | tda827xa_lna_gain(fe, 0, params); | ||
731 | |||
732 | msleep(100); | ||
733 | tuner_reg[0] = 0x60; | ||
734 | tuner_reg[1] = 0x3c; | ||
735 | tuner_transfer(fe, &msg, 1); | ||
736 | |||
737 | msleep(163); | ||
738 | tuner_reg[0] = 0x50; | ||
739 | tuner_reg[1] = 0x8f + (tda827xa_analog[i].gc3 << 4); | ||
740 | tuner_transfer(fe, &msg, 1); | ||
741 | |||
742 | tuner_reg[0] = 0x80; | ||
743 | tuner_reg[1] = 0x28; | ||
744 | tuner_transfer(fe, &msg, 1); | ||
745 | |||
746 | tuner_reg[0] = 0xb0; | ||
747 | tuner_reg[1] = 0x01; | ||
748 | tuner_transfer(fe, &msg, 1); | ||
749 | |||
750 | tuner_reg[0] = 0xc0; | ||
751 | tuner_reg[1] = 0x19 + (priv->lpsel << 1); | ||
752 | tuner_transfer(fe, &msg, 1); | ||
753 | |||
754 | priv->frequency = params->frequency; | ||
755 | |||
756 | return 0; | ||
757 | } | ||
758 | |||
759 | static void tda827xa_agcf(struct dvb_frontend *fe) | ||
760 | { | ||
761 | struct tda827x_priv *priv = fe->tuner_priv; | ||
762 | unsigned char data[] = {0x80, 0x2c}; | ||
763 | struct i2c_msg msg = {.addr = priv->i2c_addr, .flags = 0, | ||
764 | .buf = data, .len = 2}; | ||
765 | tuner_transfer(fe, &msg, 1); | ||
766 | } | ||
767 | |||
768 | /* ------------------------------------------------------------------ */ | ||
769 | |||
770 | static int tda827x_release(struct dvb_frontend *fe) | ||
771 | { | ||
772 | kfree(fe->tuner_priv); | ||
773 | fe->tuner_priv = NULL; | ||
774 | return 0; | ||
775 | } | ||
776 | |||
777 | static int tda827x_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
778 | { | ||
779 | struct tda827x_priv *priv = fe->tuner_priv; | ||
780 | *frequency = priv->frequency; | ||
781 | return 0; | ||
782 | } | ||
783 | |||
784 | static int tda827x_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) | ||
785 | { | ||
786 | struct tda827x_priv *priv = fe->tuner_priv; | ||
787 | *bandwidth = priv->bandwidth; | ||
788 | return 0; | ||
789 | } | ||
790 | |||
791 | static int tda827x_init(struct dvb_frontend *fe) | ||
792 | { | ||
793 | struct tda827x_priv *priv = fe->tuner_priv; | ||
794 | dprintk("%s:\n", __func__); | ||
795 | if (priv->cfg && priv->cfg->init) | ||
796 | priv->cfg->init(fe); | ||
797 | |||
798 | return 0; | ||
799 | } | ||
800 | |||
801 | static int tda827x_probe_version(struct dvb_frontend *fe); | ||
802 | |||
803 | static int tda827x_initial_init(struct dvb_frontend *fe) | ||
804 | { | ||
805 | int ret; | ||
806 | ret = tda827x_probe_version(fe); | ||
807 | if (ret) | ||
808 | return ret; | ||
809 | return fe->ops.tuner_ops.init(fe); | ||
810 | } | ||
811 | |||
812 | static int tda827x_initial_sleep(struct dvb_frontend *fe) | ||
813 | { | ||
814 | int ret; | ||
815 | ret = tda827x_probe_version(fe); | ||
816 | if (ret) | ||
817 | return ret; | ||
818 | return fe->ops.tuner_ops.sleep(fe); | ||
819 | } | ||
820 | |||
821 | static struct dvb_tuner_ops tda827xo_tuner_ops = { | ||
822 | .info = { | ||
823 | .name = "Philips TDA827X", | ||
824 | .frequency_min = 55000000, | ||
825 | .frequency_max = 860000000, | ||
826 | .frequency_step = 250000 | ||
827 | }, | ||
828 | .release = tda827x_release, | ||
829 | .init = tda827x_initial_init, | ||
830 | .sleep = tda827x_initial_sleep, | ||
831 | .set_params = tda827xo_set_params, | ||
832 | .set_analog_params = tda827xo_set_analog_params, | ||
833 | .get_frequency = tda827x_get_frequency, | ||
834 | .get_bandwidth = tda827x_get_bandwidth, | ||
835 | }; | ||
836 | |||
837 | static struct dvb_tuner_ops tda827xa_tuner_ops = { | ||
838 | .info = { | ||
839 | .name = "Philips TDA827XA", | ||
840 | .frequency_min = 44000000, | ||
841 | .frequency_max = 906000000, | ||
842 | .frequency_step = 62500 | ||
843 | }, | ||
844 | .release = tda827x_release, | ||
845 | .init = tda827x_init, | ||
846 | .sleep = tda827xa_sleep, | ||
847 | .set_params = tda827xa_set_params, | ||
848 | .set_analog_params = tda827xa_set_analog_params, | ||
849 | .get_frequency = tda827x_get_frequency, | ||
850 | .get_bandwidth = tda827x_get_bandwidth, | ||
851 | }; | ||
852 | |||
853 | static int tda827x_probe_version(struct dvb_frontend *fe) | ||
854 | { | ||
855 | u8 data; | ||
856 | int rc; | ||
857 | struct tda827x_priv *priv = fe->tuner_priv; | ||
858 | struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = I2C_M_RD, | ||
859 | .buf = &data, .len = 1 }; | ||
860 | |||
861 | rc = tuner_transfer(fe, &msg, 1); | ||
862 | |||
863 | if (rc < 0) { | ||
864 | printk("%s: could not read from tuner at addr: 0x%02x\n", | ||
865 | __func__, msg.addr << 1); | ||
866 | return rc; | ||
867 | } | ||
868 | if ((data & 0x3c) == 0) { | ||
869 | dprintk("tda827x tuner found\n"); | ||
870 | fe->ops.tuner_ops.init = tda827x_init; | ||
871 | fe->ops.tuner_ops.sleep = tda827xo_sleep; | ||
872 | if (priv->cfg) | ||
873 | priv->cfg->agcf = tda827xo_agcf; | ||
874 | } else { | ||
875 | dprintk("tda827xa tuner found\n"); | ||
876 | memcpy(&fe->ops.tuner_ops, &tda827xa_tuner_ops, sizeof(struct dvb_tuner_ops)); | ||
877 | if (priv->cfg) | ||
878 | priv->cfg->agcf = tda827xa_agcf; | ||
879 | } | ||
880 | return 0; | ||
881 | } | ||
882 | |||
883 | struct dvb_frontend *tda827x_attach(struct dvb_frontend *fe, int addr, | ||
884 | struct i2c_adapter *i2c, | ||
885 | struct tda827x_config *cfg) | ||
886 | { | ||
887 | struct tda827x_priv *priv = NULL; | ||
888 | |||
889 | dprintk("%s:\n", __func__); | ||
890 | priv = kzalloc(sizeof(struct tda827x_priv), GFP_KERNEL); | ||
891 | if (priv == NULL) | ||
892 | return NULL; | ||
893 | |||
894 | priv->i2c_addr = addr; | ||
895 | priv->i2c_adap = i2c; | ||
896 | priv->cfg = cfg; | ||
897 | memcpy(&fe->ops.tuner_ops, &tda827xo_tuner_ops, sizeof(struct dvb_tuner_ops)); | ||
898 | fe->tuner_priv = priv; | ||
899 | |||
900 | dprintk("type set to %s\n", fe->ops.tuner_ops.info.name); | ||
901 | |||
902 | return fe; | ||
903 | } | ||
904 | EXPORT_SYMBOL_GPL(tda827x_attach); | ||
905 | |||
906 | MODULE_DESCRIPTION("DVB TDA827x driver"); | ||
907 | MODULE_AUTHOR("Hartmut Hackmann <hartmut.hackmann@t-online.de>"); | ||
908 | MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>"); | ||
909 | MODULE_LICENSE("GPL"); | ||
910 | |||
911 | /* | ||
912 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
913 | * --------------------------------------------------------------------------- | ||
914 | * Local variables: | ||
915 | * c-basic-offset: 8 | ||
916 | * End: | ||
917 | */ | ||
diff --git a/drivers/media/tuners/tda827x.h b/drivers/media/tuners/tda827x.h new file mode 100644 index 000000000000..7d72ce0a0c2d --- /dev/null +++ b/drivers/media/tuners/tda827x.h | |||
@@ -0,0 +1,68 @@ | |||
1 | /* | ||
2 | DVB Driver for Philips tda827x / tda827xa Silicon tuners | ||
3 | |||
4 | (c) 2005 Hartmut Hackmann | ||
5 | (c) 2007 Michael Krufky | ||
6 | |||
7 | This program is free software; you can redistribute it and/or modify | ||
8 | it under the terms of the GNU General Public License as published by | ||
9 | the Free Software Foundation; either version 2 of the License, or | ||
10 | (at your option) any later version. | ||
11 | |||
12 | This program is distributed in the hope that it will be useful, | ||
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | |||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License | ||
19 | along with this program; if not, write to the Free Software | ||
20 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
21 | |||
22 | */ | ||
23 | |||
24 | #ifndef __DVB_TDA827X_H__ | ||
25 | #define __DVB_TDA827X_H__ | ||
26 | |||
27 | #include <linux/i2c.h> | ||
28 | #include "dvb_frontend.h" | ||
29 | |||
30 | struct tda827x_config | ||
31 | { | ||
32 | /* saa7134 - provided callbacks */ | ||
33 | int (*init) (struct dvb_frontend *fe); | ||
34 | int (*sleep) (struct dvb_frontend *fe); | ||
35 | |||
36 | /* interface to tda829x driver */ | ||
37 | unsigned int config; | ||
38 | int switch_addr; | ||
39 | |||
40 | void (*agcf)(struct dvb_frontend *fe); | ||
41 | }; | ||
42 | |||
43 | |||
44 | /** | ||
45 | * Attach a tda827x tuner to the supplied frontend structure. | ||
46 | * | ||
47 | * @param fe Frontend to attach to. | ||
48 | * @param addr i2c address of the tuner. | ||
49 | * @param i2c i2c adapter to use. | ||
50 | * @param cfg optional callback function pointers. | ||
51 | * @return FE pointer on success, NULL on failure. | ||
52 | */ | ||
53 | #if defined(CONFIG_MEDIA_TUNER_TDA827X) || (defined(CONFIG_MEDIA_TUNER_TDA827X_MODULE) && defined(MODULE)) | ||
54 | extern struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe, int addr, | ||
55 | struct i2c_adapter *i2c, | ||
56 | struct tda827x_config *cfg); | ||
57 | #else | ||
58 | static inline struct dvb_frontend* tda827x_attach(struct dvb_frontend *fe, | ||
59 | int addr, | ||
60 | struct i2c_adapter *i2c, | ||
61 | struct tda827x_config *cfg) | ||
62 | { | ||
63 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
64 | return NULL; | ||
65 | } | ||
66 | #endif // CONFIG_MEDIA_TUNER_TDA827X | ||
67 | |||
68 | #endif // __DVB_TDA827X_H__ | ||
diff --git a/drivers/media/tuners/tda8290.c b/drivers/media/tuners/tda8290.c new file mode 100644 index 000000000000..8c4852114eeb --- /dev/null +++ b/drivers/media/tuners/tda8290.c | |||
@@ -0,0 +1,874 @@ | |||
1 | /* | ||
2 | |||
3 | i2c tv tuner chip device driver | ||
4 | controls the philips tda8290+75 tuner chip combo. | ||
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 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | |||
20 | This "tda8290" module was split apart from the original "tuner" module. | ||
21 | */ | ||
22 | |||
23 | #include <linux/i2c.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/videodev2.h> | ||
27 | #include "tuner-i2c.h" | ||
28 | #include "tda8290.h" | ||
29 | #include "tda827x.h" | ||
30 | #include "tda18271.h" | ||
31 | |||
32 | static int debug; | ||
33 | module_param(debug, int, 0644); | ||
34 | MODULE_PARM_DESC(debug, "enable verbose debug messages"); | ||
35 | |||
36 | static int deemphasis_50; | ||
37 | module_param(deemphasis_50, int, 0644); | ||
38 | MODULE_PARM_DESC(deemphasis_50, "0 - 75us deemphasis; 1 - 50us deemphasis"); | ||
39 | |||
40 | /* ---------------------------------------------------------------------- */ | ||
41 | |||
42 | struct tda8290_priv { | ||
43 | struct tuner_i2c_props i2c_props; | ||
44 | |||
45 | unsigned char tda8290_easy_mode; | ||
46 | |||
47 | unsigned char tda827x_addr; | ||
48 | |||
49 | unsigned char ver; | ||
50 | #define TDA8290 1 | ||
51 | #define TDA8295 2 | ||
52 | #define TDA8275 4 | ||
53 | #define TDA8275A 8 | ||
54 | #define TDA18271 16 | ||
55 | |||
56 | struct tda827x_config cfg; | ||
57 | }; | ||
58 | |||
59 | /*---------------------------------------------------------------------*/ | ||
60 | |||
61 | static int tda8290_i2c_bridge(struct dvb_frontend *fe, int close) | ||
62 | { | ||
63 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
64 | |||
65 | unsigned char enable[2] = { 0x21, 0xC0 }; | ||
66 | unsigned char disable[2] = { 0x21, 0x00 }; | ||
67 | unsigned char *msg; | ||
68 | |||
69 | if (close) { | ||
70 | msg = enable; | ||
71 | tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); | ||
72 | /* let the bridge stabilize */ | ||
73 | msleep(20); | ||
74 | } else { | ||
75 | msg = disable; | ||
76 | tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); | ||
77 | } | ||
78 | |||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static int tda8295_i2c_bridge(struct dvb_frontend *fe, int close) | ||
83 | { | ||
84 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
85 | |||
86 | unsigned char enable[2] = { 0x45, 0xc1 }; | ||
87 | unsigned char disable[2] = { 0x46, 0x00 }; | ||
88 | unsigned char buf[3] = { 0x45, 0x01, 0x00 }; | ||
89 | unsigned char *msg; | ||
90 | |||
91 | if (close) { | ||
92 | msg = enable; | ||
93 | tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); | ||
94 | /* let the bridge stabilize */ | ||
95 | msleep(20); | ||
96 | } else { | ||
97 | msg = disable; | ||
98 | tuner_i2c_xfer_send_recv(&priv->i2c_props, msg, 1, &msg[1], 1); | ||
99 | |||
100 | buf[2] = msg[1]; | ||
101 | buf[2] &= ~0x04; | ||
102 | tuner_i2c_xfer_send(&priv->i2c_props, buf, 3); | ||
103 | msleep(5); | ||
104 | |||
105 | msg[1] |= 0x04; | ||
106 | tuner_i2c_xfer_send(&priv->i2c_props, msg, 2); | ||
107 | } | ||
108 | |||
109 | return 0; | ||
110 | } | ||
111 | |||
112 | /*---------------------------------------------------------------------*/ | ||
113 | |||
114 | static void set_audio(struct dvb_frontend *fe, | ||
115 | struct analog_parameters *params) | ||
116 | { | ||
117 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
118 | char* mode; | ||
119 | |||
120 | if (params->std & V4L2_STD_MN) { | ||
121 | priv->tda8290_easy_mode = 0x01; | ||
122 | mode = "MN"; | ||
123 | } else if (params->std & V4L2_STD_B) { | ||
124 | priv->tda8290_easy_mode = 0x02; | ||
125 | mode = "B"; | ||
126 | } else if (params->std & V4L2_STD_GH) { | ||
127 | priv->tda8290_easy_mode = 0x04; | ||
128 | mode = "GH"; | ||
129 | } else if (params->std & V4L2_STD_PAL_I) { | ||
130 | priv->tda8290_easy_mode = 0x08; | ||
131 | mode = "I"; | ||
132 | } else if (params->std & V4L2_STD_DK) { | ||
133 | priv->tda8290_easy_mode = 0x10; | ||
134 | mode = "DK"; | ||
135 | } else if (params->std & V4L2_STD_SECAM_L) { | ||
136 | priv->tda8290_easy_mode = 0x20; | ||
137 | mode = "L"; | ||
138 | } else if (params->std & V4L2_STD_SECAM_LC) { | ||
139 | priv->tda8290_easy_mode = 0x40; | ||
140 | mode = "LC"; | ||
141 | } else { | ||
142 | priv->tda8290_easy_mode = 0x10; | ||
143 | mode = "xx"; | ||
144 | } | ||
145 | |||
146 | if (params->mode == V4L2_TUNER_RADIO) { | ||
147 | /* Set TDA8295 to FM radio; Start TDA8290 with MN values */ | ||
148 | priv->tda8290_easy_mode = (priv->ver & TDA8295) ? 0x80 : 0x01; | ||
149 | tuner_dbg("setting to radio FM\n"); | ||
150 | } else { | ||
151 | tuner_dbg("setting tda829x to system %s\n", mode); | ||
152 | } | ||
153 | } | ||
154 | |||
155 | static struct { | ||
156 | unsigned char seq[2]; | ||
157 | } fm_mode[] = { | ||
158 | { { 0x01, 0x81} }, /* Put device into expert mode */ | ||
159 | { { 0x03, 0x48} }, /* Disable NOTCH and VIDEO filters */ | ||
160 | { { 0x04, 0x04} }, /* Disable color carrier filter (SSIF) */ | ||
161 | { { 0x05, 0x04} }, /* ADC headroom */ | ||
162 | { { 0x06, 0x10} }, /* group delay flat */ | ||
163 | |||
164 | { { 0x07, 0x00} }, /* use the same radio DTO values as a tda8295 */ | ||
165 | { { 0x08, 0x00} }, | ||
166 | { { 0x09, 0x80} }, | ||
167 | { { 0x0a, 0xda} }, | ||
168 | { { 0x0b, 0x4b} }, | ||
169 | { { 0x0c, 0x68} }, | ||
170 | |||
171 | { { 0x0d, 0x00} }, /* PLL off, no video carrier detect */ | ||
172 | { { 0x14, 0x00} }, /* disable auto mute if no video */ | ||
173 | }; | ||
174 | |||
175 | static void tda8290_set_params(struct dvb_frontend *fe, | ||
176 | struct analog_parameters *params) | ||
177 | { | ||
178 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
179 | |||
180 | unsigned char soft_reset[] = { 0x00, 0x00 }; | ||
181 | unsigned char easy_mode[] = { 0x01, priv->tda8290_easy_mode }; | ||
182 | unsigned char expert_mode[] = { 0x01, 0x80 }; | ||
183 | unsigned char agc_out_on[] = { 0x02, 0x00 }; | ||
184 | unsigned char gainset_off[] = { 0x28, 0x14 }; | ||
185 | unsigned char if_agc_spd[] = { 0x0f, 0x88 }; | ||
186 | unsigned char adc_head_6[] = { 0x05, 0x04 }; | ||
187 | unsigned char adc_head_9[] = { 0x05, 0x02 }; | ||
188 | unsigned char adc_head_12[] = { 0x05, 0x01 }; | ||
189 | unsigned char pll_bw_nom[] = { 0x0d, 0x47 }; | ||
190 | unsigned char pll_bw_low[] = { 0x0d, 0x27 }; | ||
191 | unsigned char gainset_2[] = { 0x28, 0x64 }; | ||
192 | unsigned char agc_rst_on[] = { 0x0e, 0x0b }; | ||
193 | unsigned char agc_rst_off[] = { 0x0e, 0x09 }; | ||
194 | unsigned char if_agc_set[] = { 0x0f, 0x81 }; | ||
195 | unsigned char addr_adc_sat = 0x1a; | ||
196 | unsigned char addr_agc_stat = 0x1d; | ||
197 | unsigned char addr_pll_stat = 0x1b; | ||
198 | unsigned char adc_sat, agc_stat, | ||
199 | pll_stat; | ||
200 | int i; | ||
201 | |||
202 | set_audio(fe, params); | ||
203 | |||
204 | if (priv->cfg.config) | ||
205 | tuner_dbg("tda827xa config is 0x%02x\n", priv->cfg.config); | ||
206 | tuner_i2c_xfer_send(&priv->i2c_props, easy_mode, 2); | ||
207 | tuner_i2c_xfer_send(&priv->i2c_props, agc_out_on, 2); | ||
208 | tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2); | ||
209 | msleep(1); | ||
210 | |||
211 | if (params->mode == V4L2_TUNER_RADIO) { | ||
212 | unsigned char deemphasis[] = { 0x13, 1 }; | ||
213 | |||
214 | /* FIXME: allow using a different deemphasis */ | ||
215 | |||
216 | if (deemphasis_50) | ||
217 | deemphasis[1] = 2; | ||
218 | |||
219 | for (i = 0; i < ARRAY_SIZE(fm_mode); i++) | ||
220 | tuner_i2c_xfer_send(&priv->i2c_props, fm_mode[i].seq, 2); | ||
221 | |||
222 | tuner_i2c_xfer_send(&priv->i2c_props, deemphasis, 2); | ||
223 | } else { | ||
224 | expert_mode[1] = priv->tda8290_easy_mode + 0x80; | ||
225 | tuner_i2c_xfer_send(&priv->i2c_props, expert_mode, 2); | ||
226 | tuner_i2c_xfer_send(&priv->i2c_props, gainset_off, 2); | ||
227 | tuner_i2c_xfer_send(&priv->i2c_props, if_agc_spd, 2); | ||
228 | if (priv->tda8290_easy_mode & 0x60) | ||
229 | tuner_i2c_xfer_send(&priv->i2c_props, adc_head_9, 2); | ||
230 | else | ||
231 | tuner_i2c_xfer_send(&priv->i2c_props, adc_head_6, 2); | ||
232 | tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2); | ||
233 | } | ||
234 | |||
235 | |||
236 | tda8290_i2c_bridge(fe, 1); | ||
237 | |||
238 | if (fe->ops.tuner_ops.set_analog_params) | ||
239 | fe->ops.tuner_ops.set_analog_params(fe, params); | ||
240 | |||
241 | for (i = 0; i < 3; i++) { | ||
242 | tuner_i2c_xfer_send_recv(&priv->i2c_props, | ||
243 | &addr_pll_stat, 1, &pll_stat, 1); | ||
244 | if (pll_stat & 0x80) { | ||
245 | tuner_i2c_xfer_send_recv(&priv->i2c_props, | ||
246 | &addr_adc_sat, 1, | ||
247 | &adc_sat, 1); | ||
248 | tuner_i2c_xfer_send_recv(&priv->i2c_props, | ||
249 | &addr_agc_stat, 1, | ||
250 | &agc_stat, 1); | ||
251 | tuner_dbg("tda8290 is locked, AGC: %d\n", agc_stat); | ||
252 | break; | ||
253 | } else { | ||
254 | tuner_dbg("tda8290 not locked, no signal?\n"); | ||
255 | msleep(100); | ||
256 | } | ||
257 | } | ||
258 | /* adjust headroom resp. gain */ | ||
259 | if ((agc_stat > 115) || (!(pll_stat & 0x80) && (adc_sat < 20))) { | ||
260 | tuner_dbg("adjust gain, step 1. Agc: %d, ADC stat: %d, lock: %d\n", | ||
261 | agc_stat, adc_sat, pll_stat & 0x80); | ||
262 | tuner_i2c_xfer_send(&priv->i2c_props, gainset_2, 2); | ||
263 | msleep(100); | ||
264 | tuner_i2c_xfer_send_recv(&priv->i2c_props, | ||
265 | &addr_agc_stat, 1, &agc_stat, 1); | ||
266 | tuner_i2c_xfer_send_recv(&priv->i2c_props, | ||
267 | &addr_pll_stat, 1, &pll_stat, 1); | ||
268 | if ((agc_stat > 115) || !(pll_stat & 0x80)) { | ||
269 | tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n", | ||
270 | agc_stat, pll_stat & 0x80); | ||
271 | if (priv->cfg.agcf) | ||
272 | priv->cfg.agcf(fe); | ||
273 | msleep(100); | ||
274 | tuner_i2c_xfer_send_recv(&priv->i2c_props, | ||
275 | &addr_agc_stat, 1, | ||
276 | &agc_stat, 1); | ||
277 | tuner_i2c_xfer_send_recv(&priv->i2c_props, | ||
278 | &addr_pll_stat, 1, | ||
279 | &pll_stat, 1); | ||
280 | if((agc_stat > 115) || !(pll_stat & 0x80)) { | ||
281 | tuner_dbg("adjust gain, step 3. Agc: %d\n", agc_stat); | ||
282 | tuner_i2c_xfer_send(&priv->i2c_props, adc_head_12, 2); | ||
283 | tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_low, 2); | ||
284 | msleep(100); | ||
285 | } | ||
286 | } | ||
287 | } | ||
288 | |||
289 | /* l/ l' deadlock? */ | ||
290 | if(priv->tda8290_easy_mode & 0x60) { | ||
291 | tuner_i2c_xfer_send_recv(&priv->i2c_props, | ||
292 | &addr_adc_sat, 1, | ||
293 | &adc_sat, 1); | ||
294 | tuner_i2c_xfer_send_recv(&priv->i2c_props, | ||
295 | &addr_pll_stat, 1, | ||
296 | &pll_stat, 1); | ||
297 | if ((adc_sat > 20) || !(pll_stat & 0x80)) { | ||
298 | tuner_dbg("trying to resolve SECAM L deadlock\n"); | ||
299 | tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_on, 2); | ||
300 | msleep(40); | ||
301 | tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_off, 2); | ||
302 | } | ||
303 | } | ||
304 | |||
305 | tda8290_i2c_bridge(fe, 0); | ||
306 | tuner_i2c_xfer_send(&priv->i2c_props, if_agc_set, 2); | ||
307 | } | ||
308 | |||
309 | /*---------------------------------------------------------------------*/ | ||
310 | |||
311 | static void tda8295_power(struct dvb_frontend *fe, int enable) | ||
312 | { | ||
313 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
314 | unsigned char buf[] = { 0x30, 0x00 }; /* clb_stdbt */ | ||
315 | |||
316 | tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1); | ||
317 | |||
318 | if (enable) | ||
319 | buf[1] = 0x01; | ||
320 | else | ||
321 | buf[1] = 0x03; | ||
322 | |||
323 | tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); | ||
324 | } | ||
325 | |||
326 | static void tda8295_set_easy_mode(struct dvb_frontend *fe, int enable) | ||
327 | { | ||
328 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
329 | unsigned char buf[] = { 0x01, 0x00 }; | ||
330 | |||
331 | tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1); | ||
332 | |||
333 | if (enable) | ||
334 | buf[1] = 0x01; /* rising edge sets regs 0x02 - 0x23 */ | ||
335 | else | ||
336 | buf[1] = 0x00; /* reset active bit */ | ||
337 | |||
338 | tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); | ||
339 | } | ||
340 | |||
341 | static void tda8295_set_video_std(struct dvb_frontend *fe) | ||
342 | { | ||
343 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
344 | unsigned char buf[] = { 0x00, priv->tda8290_easy_mode }; | ||
345 | |||
346 | tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); | ||
347 | |||
348 | tda8295_set_easy_mode(fe, 1); | ||
349 | msleep(20); | ||
350 | tda8295_set_easy_mode(fe, 0); | ||
351 | } | ||
352 | |||
353 | /*---------------------------------------------------------------------*/ | ||
354 | |||
355 | static void tda8295_agc1_out(struct dvb_frontend *fe, int enable) | ||
356 | { | ||
357 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
358 | unsigned char buf[] = { 0x02, 0x00 }; /* DIV_FUNC */ | ||
359 | |||
360 | tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1); | ||
361 | |||
362 | if (enable) | ||
363 | buf[1] &= ~0x40; | ||
364 | else | ||
365 | buf[1] |= 0x40; | ||
366 | |||
367 | tuner_i2c_xfer_send(&priv->i2c_props, buf, 2); | ||
368 | } | ||
369 | |||
370 | static void tda8295_agc2_out(struct dvb_frontend *fe, int enable) | ||
371 | { | ||
372 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
373 | unsigned char set_gpio_cf[] = { 0x44, 0x00 }; | ||
374 | unsigned char set_gpio_val[] = { 0x46, 0x00 }; | ||
375 | |||
376 | tuner_i2c_xfer_send_recv(&priv->i2c_props, | ||
377 | &set_gpio_cf[0], 1, &set_gpio_cf[1], 1); | ||
378 | tuner_i2c_xfer_send_recv(&priv->i2c_props, | ||
379 | &set_gpio_val[0], 1, &set_gpio_val[1], 1); | ||
380 | |||
381 | set_gpio_cf[1] &= 0xf0; /* clear GPIO_0 bits 3-0 */ | ||
382 | |||
383 | if (enable) { | ||
384 | set_gpio_cf[1] |= 0x01; /* config GPIO_0 as Open Drain Out */ | ||
385 | set_gpio_val[1] &= 0xfe; /* set GPIO_0 pin low */ | ||
386 | } | ||
387 | tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_cf, 2); | ||
388 | tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_val, 2); | ||
389 | } | ||
390 | |||
391 | static int tda8295_has_signal(struct dvb_frontend *fe) | ||
392 | { | ||
393 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
394 | |||
395 | unsigned char hvpll_stat = 0x26; | ||
396 | unsigned char ret; | ||
397 | |||
398 | tuner_i2c_xfer_send_recv(&priv->i2c_props, &hvpll_stat, 1, &ret, 1); | ||
399 | return (ret & 0x01) ? 65535 : 0; | ||
400 | } | ||
401 | |||
402 | /*---------------------------------------------------------------------*/ | ||
403 | |||
404 | static void tda8295_set_params(struct dvb_frontend *fe, | ||
405 | struct analog_parameters *params) | ||
406 | { | ||
407 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
408 | |||
409 | unsigned char blanking_mode[] = { 0x1d, 0x00 }; | ||
410 | |||
411 | set_audio(fe, params); | ||
412 | |||
413 | tuner_dbg("%s: freq = %d\n", __func__, params->frequency); | ||
414 | |||
415 | tda8295_power(fe, 1); | ||
416 | tda8295_agc1_out(fe, 1); | ||
417 | |||
418 | tuner_i2c_xfer_send_recv(&priv->i2c_props, | ||
419 | &blanking_mode[0], 1, &blanking_mode[1], 1); | ||
420 | |||
421 | tda8295_set_video_std(fe); | ||
422 | |||
423 | blanking_mode[1] = 0x03; | ||
424 | tuner_i2c_xfer_send(&priv->i2c_props, blanking_mode, 2); | ||
425 | msleep(20); | ||
426 | |||
427 | tda8295_i2c_bridge(fe, 1); | ||
428 | |||
429 | if (fe->ops.tuner_ops.set_analog_params) | ||
430 | fe->ops.tuner_ops.set_analog_params(fe, params); | ||
431 | |||
432 | if (priv->cfg.agcf) | ||
433 | priv->cfg.agcf(fe); | ||
434 | |||
435 | if (tda8295_has_signal(fe)) | ||
436 | tuner_dbg("tda8295 is locked\n"); | ||
437 | else | ||
438 | tuner_dbg("tda8295 not locked, no signal?\n"); | ||
439 | |||
440 | tda8295_i2c_bridge(fe, 0); | ||
441 | } | ||
442 | |||
443 | /*---------------------------------------------------------------------*/ | ||
444 | |||
445 | static int tda8290_has_signal(struct dvb_frontend *fe) | ||
446 | { | ||
447 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
448 | |||
449 | unsigned char i2c_get_afc[1] = { 0x1B }; | ||
450 | unsigned char afc = 0; | ||
451 | |||
452 | tuner_i2c_xfer_send_recv(&priv->i2c_props, | ||
453 | i2c_get_afc, ARRAY_SIZE(i2c_get_afc), &afc, 1); | ||
454 | return (afc & 0x80)? 65535:0; | ||
455 | } | ||
456 | |||
457 | /*---------------------------------------------------------------------*/ | ||
458 | |||
459 | static void tda8290_standby(struct dvb_frontend *fe) | ||
460 | { | ||
461 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
462 | |||
463 | unsigned char cb1[] = { 0x30, 0xD0 }; | ||
464 | unsigned char tda8290_standby[] = { 0x00, 0x02 }; | ||
465 | unsigned char tda8290_agc_tri[] = { 0x02, 0x20 }; | ||
466 | struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, .buf=cb1, .len = 2}; | ||
467 | |||
468 | tda8290_i2c_bridge(fe, 1); | ||
469 | if (priv->ver & TDA8275A) | ||
470 | cb1[1] = 0x90; | ||
471 | i2c_transfer(priv->i2c_props.adap, &msg, 1); | ||
472 | tda8290_i2c_bridge(fe, 0); | ||
473 | tuner_i2c_xfer_send(&priv->i2c_props, tda8290_agc_tri, 2); | ||
474 | tuner_i2c_xfer_send(&priv->i2c_props, tda8290_standby, 2); | ||
475 | } | ||
476 | |||
477 | static void tda8295_standby(struct dvb_frontend *fe) | ||
478 | { | ||
479 | tda8295_agc1_out(fe, 0); /* Put AGC in tri-state */ | ||
480 | |||
481 | tda8295_power(fe, 0); | ||
482 | } | ||
483 | |||
484 | static void tda8290_init_if(struct dvb_frontend *fe) | ||
485 | { | ||
486 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
487 | |||
488 | unsigned char set_VS[] = { 0x30, 0x6F }; | ||
489 | unsigned char set_GP00_CF[] = { 0x20, 0x01 }; | ||
490 | unsigned char set_GP01_CF[] = { 0x20, 0x0B }; | ||
491 | |||
492 | if ((priv->cfg.config == 1) || (priv->cfg.config == 2)) | ||
493 | tuner_i2c_xfer_send(&priv->i2c_props, set_GP00_CF, 2); | ||
494 | else | ||
495 | tuner_i2c_xfer_send(&priv->i2c_props, set_GP01_CF, 2); | ||
496 | tuner_i2c_xfer_send(&priv->i2c_props, set_VS, 2); | ||
497 | } | ||
498 | |||
499 | static void tda8295_init_if(struct dvb_frontend *fe) | ||
500 | { | ||
501 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
502 | |||
503 | static unsigned char set_adc_ctl[] = { 0x33, 0x14 }; | ||
504 | static unsigned char set_adc_ctl2[] = { 0x34, 0x00 }; | ||
505 | static unsigned char set_pll_reg6[] = { 0x3e, 0x63 }; | ||
506 | static unsigned char set_pll_reg0[] = { 0x38, 0x23 }; | ||
507 | static unsigned char set_pll_reg7[] = { 0x3f, 0x01 }; | ||
508 | static unsigned char set_pll_reg10[] = { 0x42, 0x61 }; | ||
509 | static unsigned char set_gpio_reg0[] = { 0x44, 0x0b }; | ||
510 | |||
511 | tda8295_power(fe, 1); | ||
512 | |||
513 | tda8295_set_easy_mode(fe, 0); | ||
514 | tda8295_set_video_std(fe); | ||
515 | |||
516 | tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl, 2); | ||
517 | tuner_i2c_xfer_send(&priv->i2c_props, set_adc_ctl2, 2); | ||
518 | tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg6, 2); | ||
519 | tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg0, 2); | ||
520 | tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg7, 2); | ||
521 | tuner_i2c_xfer_send(&priv->i2c_props, set_pll_reg10, 2); | ||
522 | tuner_i2c_xfer_send(&priv->i2c_props, set_gpio_reg0, 2); | ||
523 | |||
524 | tda8295_agc1_out(fe, 0); | ||
525 | tda8295_agc2_out(fe, 0); | ||
526 | } | ||
527 | |||
528 | static void tda8290_init_tuner(struct dvb_frontend *fe) | ||
529 | { | ||
530 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
531 | unsigned char tda8275_init[] = { 0x00, 0x00, 0x00, 0x40, 0xdC, 0x04, 0xAf, | ||
532 | 0x3F, 0x2A, 0x04, 0xFF, 0x00, 0x00, 0x40 }; | ||
533 | unsigned char tda8275a_init[] = { 0x00, 0x00, 0x00, 0x00, 0xdC, 0x05, 0x8b, | ||
534 | 0x0c, 0x04, 0x20, 0xFF, 0x00, 0x00, 0x4b }; | ||
535 | struct i2c_msg msg = {.addr = priv->tda827x_addr, .flags=0, | ||
536 | .buf=tda8275_init, .len = 14}; | ||
537 | if (priv->ver & TDA8275A) | ||
538 | msg.buf = tda8275a_init; | ||
539 | |||
540 | tda8290_i2c_bridge(fe, 1); | ||
541 | i2c_transfer(priv->i2c_props.adap, &msg, 1); | ||
542 | tda8290_i2c_bridge(fe, 0); | ||
543 | } | ||
544 | |||
545 | /*---------------------------------------------------------------------*/ | ||
546 | |||
547 | static void tda829x_release(struct dvb_frontend *fe) | ||
548 | { | ||
549 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
550 | |||
551 | /* only try to release the tuner if we've | ||
552 | * attached it from within this module */ | ||
553 | if (priv->ver & (TDA18271 | TDA8275 | TDA8275A)) | ||
554 | if (fe->ops.tuner_ops.release) | ||
555 | fe->ops.tuner_ops.release(fe); | ||
556 | |||
557 | kfree(fe->analog_demod_priv); | ||
558 | fe->analog_demod_priv = NULL; | ||
559 | } | ||
560 | |||
561 | static struct tda18271_config tda829x_tda18271_config = { | ||
562 | .gate = TDA18271_GATE_ANALOG, | ||
563 | }; | ||
564 | |||
565 | static int tda829x_find_tuner(struct dvb_frontend *fe) | ||
566 | { | ||
567 | struct tda8290_priv *priv = fe->analog_demod_priv; | ||
568 | struct analog_demod_ops *analog_ops = &fe->ops.analog_ops; | ||
569 | int i, ret, tuners_found; | ||
570 | u32 tuner_addrs; | ||
571 | u8 data; | ||
572 | struct i2c_msg msg = { .flags = I2C_M_RD, .buf = &data, .len = 1 }; | ||
573 | |||
574 | if (!analog_ops->i2c_gate_ctrl) { | ||
575 | printk(KERN_ERR "tda8290: no gate control were provided!\n"); | ||
576 | |||
577 | return -EINVAL; | ||
578 | } | ||
579 | |||
580 | analog_ops->i2c_gate_ctrl(fe, 1); | ||
581 | |||
582 | /* probe for tuner chip */ | ||
583 | tuners_found = 0; | ||
584 | tuner_addrs = 0; | ||
585 | for (i = 0x60; i <= 0x63; i++) { | ||
586 | msg.addr = i; | ||
587 | ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); | ||
588 | if (ret == 1) { | ||
589 | tuners_found++; | ||
590 | tuner_addrs = (tuner_addrs << 8) + i; | ||
591 | } | ||
592 | } | ||
593 | /* if there is more than one tuner, we expect the right one is | ||
594 | behind the bridge and we choose the highest address that doesn't | ||
595 | give a response now | ||
596 | */ | ||
597 | |||
598 | analog_ops->i2c_gate_ctrl(fe, 0); | ||
599 | |||
600 | if (tuners_found > 1) | ||
601 | for (i = 0; i < tuners_found; i++) { | ||
602 | msg.addr = tuner_addrs & 0xff; | ||
603 | ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); | ||
604 | if (ret == 1) | ||
605 | tuner_addrs = tuner_addrs >> 8; | ||
606 | else | ||
607 | break; | ||
608 | } | ||
609 | |||
610 | if (tuner_addrs == 0) { | ||
611 | tuner_addrs = 0x60; | ||
612 | tuner_info("could not clearly identify tuner address, " | ||
613 | "defaulting to %x\n", tuner_addrs); | ||
614 | } else { | ||
615 | tuner_addrs = tuner_addrs & 0xff; | ||
616 | tuner_info("setting tuner address to %x\n", tuner_addrs); | ||
617 | } | ||
618 | priv->tda827x_addr = tuner_addrs; | ||
619 | msg.addr = tuner_addrs; | ||
620 | |||
621 | analog_ops->i2c_gate_ctrl(fe, 1); | ||
622 | ret = i2c_transfer(priv->i2c_props.adap, &msg, 1); | ||
623 | |||
624 | if (ret != 1) { | ||
625 | tuner_warn("tuner access failed!\n"); | ||
626 | analog_ops->i2c_gate_ctrl(fe, 0); | ||
627 | return -EREMOTEIO; | ||
628 | } | ||
629 | |||
630 | if ((data == 0x83) || (data == 0x84)) { | ||
631 | priv->ver |= TDA18271; | ||
632 | tda829x_tda18271_config.config = priv->cfg.config; | ||
633 | dvb_attach(tda18271_attach, fe, priv->tda827x_addr, | ||
634 | priv->i2c_props.adap, &tda829x_tda18271_config); | ||
635 | } else { | ||
636 | if ((data & 0x3c) == 0) | ||
637 | priv->ver |= TDA8275; | ||
638 | else | ||
639 | priv->ver |= TDA8275A; | ||
640 | |||
641 | dvb_attach(tda827x_attach, fe, priv->tda827x_addr, | ||
642 | priv->i2c_props.adap, &priv->cfg); | ||
643 | priv->cfg.switch_addr = priv->i2c_props.addr; | ||
644 | } | ||
645 | if (fe->ops.tuner_ops.init) | ||
646 | fe->ops.tuner_ops.init(fe); | ||
647 | |||
648 | if (fe->ops.tuner_ops.sleep) | ||
649 | fe->ops.tuner_ops.sleep(fe); | ||
650 | |||
651 | analog_ops->i2c_gate_ctrl(fe, 0); | ||
652 | |||
653 | return 0; | ||
654 | } | ||
655 | |||
656 | static int tda8290_probe(struct tuner_i2c_props *i2c_props) | ||
657 | { | ||
658 | #define TDA8290_ID 0x89 | ||
659 | u8 reg = 0x1f, id; | ||
660 | struct i2c_msg msg_read[] = { | ||
661 | { .addr = i2c_props->addr, .flags = 0, .len = 1, .buf = ® }, | ||
662 | { .addr = i2c_props->addr, .flags = I2C_M_RD, .len = 1, .buf = &id }, | ||
663 | }; | ||
664 | |||
665 | /* detect tda8290 */ | ||
666 | if (i2c_transfer(i2c_props->adap, msg_read, 2) != 2) { | ||
667 | printk(KERN_WARNING "%s: couldn't read register 0x%02x\n", | ||
668 | __func__, reg); | ||
669 | return -ENODEV; | ||
670 | } | ||
671 | |||
672 | if (id == TDA8290_ID) { | ||
673 | if (debug) | ||
674 | printk(KERN_DEBUG "%s: tda8290 detected @ %d-%04x\n", | ||
675 | __func__, i2c_adapter_id(i2c_props->adap), | ||
676 | i2c_props->addr); | ||
677 | return 0; | ||
678 | } | ||
679 | return -ENODEV; | ||
680 | } | ||
681 | |||
682 | static int tda8295_probe(struct tuner_i2c_props *i2c_props) | ||
683 | { | ||
684 | #define TDA8295_ID 0x8a | ||
685 | #define TDA8295C2_ID 0x8b | ||
686 | u8 reg = 0x2f, id; | ||
687 | struct i2c_msg msg_read[] = { | ||
688 | { .addr = i2c_props->addr, .flags = 0, .len = 1, .buf = ® }, | ||
689 | { .addr = i2c_props->addr, .flags = I2C_M_RD, .len = 1, .buf = &id }, | ||
690 | }; | ||
691 | |||
692 | /* detect tda8295 */ | ||
693 | if (i2c_transfer(i2c_props->adap, msg_read, 2) != 2) { | ||
694 | printk(KERN_WARNING "%s: couldn't read register 0x%02x\n", | ||
695 | __func__, reg); | ||
696 | return -ENODEV; | ||
697 | } | ||
698 | |||
699 | if ((id & 0xfe) == TDA8295_ID) { | ||
700 | if (debug) | ||
701 | printk(KERN_DEBUG "%s: %s detected @ %d-%04x\n", | ||
702 | __func__, (id == TDA8295_ID) ? | ||
703 | "tda8295c1" : "tda8295c2", | ||
704 | i2c_adapter_id(i2c_props->adap), | ||
705 | i2c_props->addr); | ||
706 | return 0; | ||
707 | } | ||
708 | |||
709 | return -ENODEV; | ||
710 | } | ||
711 | |||
712 | static struct analog_demod_ops tda8290_ops = { | ||
713 | .set_params = tda8290_set_params, | ||
714 | .has_signal = tda8290_has_signal, | ||
715 | .standby = tda8290_standby, | ||
716 | .release = tda829x_release, | ||
717 | .i2c_gate_ctrl = tda8290_i2c_bridge, | ||
718 | }; | ||
719 | |||
720 | static struct analog_demod_ops tda8295_ops = { | ||
721 | .set_params = tda8295_set_params, | ||
722 | .has_signal = tda8295_has_signal, | ||
723 | .standby = tda8295_standby, | ||
724 | .release = tda829x_release, | ||
725 | .i2c_gate_ctrl = tda8295_i2c_bridge, | ||
726 | }; | ||
727 | |||
728 | struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, | ||
729 | struct i2c_adapter *i2c_adap, u8 i2c_addr, | ||
730 | struct tda829x_config *cfg) | ||
731 | { | ||
732 | struct tda8290_priv *priv = NULL; | ||
733 | char *name; | ||
734 | |||
735 | priv = kzalloc(sizeof(struct tda8290_priv), GFP_KERNEL); | ||
736 | if (priv == NULL) | ||
737 | return NULL; | ||
738 | fe->analog_demod_priv = priv; | ||
739 | |||
740 | priv->i2c_props.addr = i2c_addr; | ||
741 | priv->i2c_props.adap = i2c_adap; | ||
742 | priv->i2c_props.name = "tda829x"; | ||
743 | if (cfg) | ||
744 | priv->cfg.config = cfg->lna_cfg; | ||
745 | |||
746 | if (tda8290_probe(&priv->i2c_props) == 0) { | ||
747 | priv->ver = TDA8290; | ||
748 | memcpy(&fe->ops.analog_ops, &tda8290_ops, | ||
749 | sizeof(struct analog_demod_ops)); | ||
750 | } | ||
751 | |||
752 | if (tda8295_probe(&priv->i2c_props) == 0) { | ||
753 | priv->ver = TDA8295; | ||
754 | memcpy(&fe->ops.analog_ops, &tda8295_ops, | ||
755 | sizeof(struct analog_demod_ops)); | ||
756 | } | ||
757 | |||
758 | if (!(cfg) || (TDA829X_PROBE_TUNER == cfg->probe_tuner)) { | ||
759 | tda8295_power(fe, 1); | ||
760 | if (tda829x_find_tuner(fe) < 0) | ||
761 | goto fail; | ||
762 | } | ||
763 | |||
764 | switch (priv->ver) { | ||
765 | case TDA8290: | ||
766 | name = "tda8290"; | ||
767 | break; | ||
768 | case TDA8295: | ||
769 | name = "tda8295"; | ||
770 | break; | ||
771 | case TDA8290 | TDA8275: | ||
772 | name = "tda8290+75"; | ||
773 | break; | ||
774 | case TDA8295 | TDA8275: | ||
775 | name = "tda8295+75"; | ||
776 | break; | ||
777 | case TDA8290 | TDA8275A: | ||
778 | name = "tda8290+75a"; | ||
779 | break; | ||
780 | case TDA8295 | TDA8275A: | ||
781 | name = "tda8295+75a"; | ||
782 | break; | ||
783 | case TDA8290 | TDA18271: | ||
784 | name = "tda8290+18271"; | ||
785 | break; | ||
786 | case TDA8295 | TDA18271: | ||
787 | name = "tda8295+18271"; | ||
788 | break; | ||
789 | default: | ||
790 | goto fail; | ||
791 | } | ||
792 | tuner_info("type set to %s\n", name); | ||
793 | |||
794 | fe->ops.analog_ops.info.name = name; | ||
795 | |||
796 | if (priv->ver & TDA8290) { | ||
797 | if (priv->ver & (TDA8275 | TDA8275A)) | ||
798 | tda8290_init_tuner(fe); | ||
799 | tda8290_init_if(fe); | ||
800 | } else if (priv->ver & TDA8295) | ||
801 | tda8295_init_if(fe); | ||
802 | |||
803 | return fe; | ||
804 | |||
805 | fail: | ||
806 | memset(&fe->ops.analog_ops, 0, sizeof(struct analog_demod_ops)); | ||
807 | |||
808 | tda829x_release(fe); | ||
809 | return NULL; | ||
810 | } | ||
811 | EXPORT_SYMBOL_GPL(tda829x_attach); | ||
812 | |||
813 | int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr) | ||
814 | { | ||
815 | struct tuner_i2c_props i2c_props = { | ||
816 | .adap = i2c_adap, | ||
817 | .addr = i2c_addr, | ||
818 | }; | ||
819 | |||
820 | unsigned char soft_reset[] = { 0x00, 0x00 }; | ||
821 | unsigned char easy_mode_b[] = { 0x01, 0x02 }; | ||
822 | unsigned char easy_mode_g[] = { 0x01, 0x04 }; | ||
823 | unsigned char restore_9886[] = { 0x00, 0xd6, 0x30 }; | ||
824 | unsigned char addr_dto_lsb = 0x07; | ||
825 | unsigned char data; | ||
826 | #define PROBE_BUFFER_SIZE 8 | ||
827 | unsigned char buf[PROBE_BUFFER_SIZE]; | ||
828 | int i; | ||
829 | |||
830 | /* rule out tda9887, which would return the same byte repeatedly */ | ||
831 | tuner_i2c_xfer_send_recv(&i2c_props, | ||
832 | soft_reset, 1, buf, PROBE_BUFFER_SIZE); | ||
833 | for (i = 1; i < PROBE_BUFFER_SIZE; i++) { | ||
834 | if (buf[i] != buf[0]) | ||
835 | break; | ||
836 | } | ||
837 | |||
838 | /* all bytes are equal, not a tda829x - probably a tda9887 */ | ||
839 | if (i == PROBE_BUFFER_SIZE) | ||
840 | return -ENODEV; | ||
841 | |||
842 | if ((tda8290_probe(&i2c_props) == 0) || | ||
843 | (tda8295_probe(&i2c_props) == 0)) | ||
844 | return 0; | ||
845 | |||
846 | /* fall back to old probing method */ | ||
847 | tuner_i2c_xfer_send(&i2c_props, easy_mode_b, 2); | ||
848 | tuner_i2c_xfer_send(&i2c_props, soft_reset, 2); | ||
849 | tuner_i2c_xfer_send_recv(&i2c_props, &addr_dto_lsb, 1, &data, 1); | ||
850 | if (data == 0) { | ||
851 | tuner_i2c_xfer_send(&i2c_props, easy_mode_g, 2); | ||
852 | tuner_i2c_xfer_send(&i2c_props, soft_reset, 2); | ||
853 | tuner_i2c_xfer_send_recv(&i2c_props, | ||
854 | &addr_dto_lsb, 1, &data, 1); | ||
855 | if (data == 0x7b) { | ||
856 | return 0; | ||
857 | } | ||
858 | } | ||
859 | tuner_i2c_xfer_send(&i2c_props, restore_9886, 3); | ||
860 | return -ENODEV; | ||
861 | } | ||
862 | EXPORT_SYMBOL_GPL(tda829x_probe); | ||
863 | |||
864 | MODULE_DESCRIPTION("Philips/NXP TDA8290/TDA8295 analog IF demodulator driver"); | ||
865 | MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann, Michael Krufky"); | ||
866 | MODULE_LICENSE("GPL"); | ||
867 | |||
868 | /* | ||
869 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
870 | * --------------------------------------------------------------------------- | ||
871 | * Local variables: | ||
872 | * c-basic-offset: 8 | ||
873 | * End: | ||
874 | */ | ||
diff --git a/drivers/media/tuners/tda8290.h b/drivers/media/tuners/tda8290.h new file mode 100644 index 000000000000..7e288b26fcc3 --- /dev/null +++ b/drivers/media/tuners/tda8290.h | |||
@@ -0,0 +1,56 @@ | |||
1 | /* | ||
2 | This program is free software; you can redistribute it and/or modify | ||
3 | it under the terms of the GNU General Public License as published by | ||
4 | the Free Software Foundation; either version 2 of the License, or | ||
5 | (at your option) any later version. | ||
6 | |||
7 | This program is distributed in the hope that it will be useful, | ||
8 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | GNU General Public License for more details. | ||
11 | |||
12 | You should have received a copy of the GNU General Public License | ||
13 | along with this program; if not, write to the Free Software | ||
14 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
15 | */ | ||
16 | |||
17 | #ifndef __TDA8290_H__ | ||
18 | #define __TDA8290_H__ | ||
19 | |||
20 | #include <linux/i2c.h> | ||
21 | #include "dvb_frontend.h" | ||
22 | |||
23 | struct tda829x_config { | ||
24 | unsigned int lna_cfg; | ||
25 | |||
26 | unsigned int probe_tuner:1; | ||
27 | #define TDA829X_PROBE_TUNER 0 | ||
28 | #define TDA829X_DONT_PROBE 1 | ||
29 | }; | ||
30 | |||
31 | #if defined(CONFIG_MEDIA_TUNER_TDA8290) || (defined(CONFIG_MEDIA_TUNER_TDA8290_MODULE) && defined(MODULE)) | ||
32 | extern int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr); | ||
33 | |||
34 | extern struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, | ||
35 | struct i2c_adapter *i2c_adap, | ||
36 | u8 i2c_addr, | ||
37 | struct tda829x_config *cfg); | ||
38 | #else | ||
39 | static inline int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr) | ||
40 | { | ||
41 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
42 | return -EINVAL; | ||
43 | } | ||
44 | |||
45 | static inline struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe, | ||
46 | struct i2c_adapter *i2c_adap, | ||
47 | u8 i2c_addr, | ||
48 | struct tda829x_config *cfg) | ||
49 | { | ||
50 | printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", | ||
51 | __func__); | ||
52 | return NULL; | ||
53 | } | ||
54 | #endif | ||
55 | |||
56 | #endif /* __TDA8290_H__ */ | ||
diff --git a/drivers/media/tuners/tda9887.c b/drivers/media/tuners/tda9887.c new file mode 100644 index 000000000000..cdb645d57438 --- /dev/null +++ b/drivers/media/tuners/tda9887.c | |||
@@ -0,0 +1,717 @@ | |||
1 | #include <linux/module.h> | ||
2 | #include <linux/kernel.h> | ||
3 | #include <linux/i2c.h> | ||
4 | #include <linux/types.h> | ||
5 | #include <linux/init.h> | ||
6 | #include <linux/errno.h> | ||
7 | #include <linux/delay.h> | ||
8 | #include <linux/videodev2.h> | ||
9 | #include <media/v4l2-common.h> | ||
10 | #include <media/tuner.h> | ||
11 | #include "tuner-i2c.h" | ||
12 | #include "tda9887.h" | ||
13 | |||
14 | |||
15 | /* Chips: | ||
16 | TDA9885 (PAL, NTSC) | ||
17 | TDA9886 (PAL, SECAM, NTSC) | ||
18 | TDA9887 (PAL, SECAM, NTSC, FM Radio) | ||
19 | |||
20 | Used as part of several tuners | ||
21 | */ | ||
22 | |||
23 | static int debug; | ||
24 | module_param(debug, int, 0644); | ||
25 | MODULE_PARM_DESC(debug, "enable verbose debug messages"); | ||
26 | |||
27 | static DEFINE_MUTEX(tda9887_list_mutex); | ||
28 | static LIST_HEAD(hybrid_tuner_instance_list); | ||
29 | |||
30 | struct tda9887_priv { | ||
31 | struct tuner_i2c_props i2c_props; | ||
32 | struct list_head hybrid_tuner_instance_list; | ||
33 | |||
34 | unsigned char data[4]; | ||
35 | unsigned int config; | ||
36 | unsigned int mode; | ||
37 | unsigned int audmode; | ||
38 | v4l2_std_id std; | ||
39 | |||
40 | bool standby; | ||
41 | }; | ||
42 | |||
43 | /* ---------------------------------------------------------------------- */ | ||
44 | |||
45 | #define UNSET (-1U) | ||
46 | |||
47 | struct tvnorm { | ||
48 | v4l2_std_id std; | ||
49 | char *name; | ||
50 | unsigned char b; | ||
51 | unsigned char c; | ||
52 | unsigned char e; | ||
53 | }; | ||
54 | |||
55 | /* ---------------------------------------------------------------------- */ | ||
56 | |||
57 | // | ||
58 | // TDA defines | ||
59 | // | ||
60 | |||
61 | //// first reg (b) | ||
62 | #define cVideoTrapBypassOFF 0x00 // bit b0 | ||
63 | #define cVideoTrapBypassON 0x01 // bit b0 | ||
64 | |||
65 | #define cAutoMuteFmInactive 0x00 // bit b1 | ||
66 | #define cAutoMuteFmActive 0x02 // bit b1 | ||
67 | |||
68 | #define cIntercarrier 0x00 // bit b2 | ||
69 | #define cQSS 0x04 // bit b2 | ||
70 | |||
71 | #define cPositiveAmTV 0x00 // bit b3:4 | ||
72 | #define cFmRadio 0x08 // bit b3:4 | ||
73 | #define cNegativeFmTV 0x10 // bit b3:4 | ||
74 | |||
75 | |||
76 | #define cForcedMuteAudioON 0x20 // bit b5 | ||
77 | #define cForcedMuteAudioOFF 0x00 // bit b5 | ||
78 | |||
79 | #define cOutputPort1Active 0x00 // bit b6 | ||
80 | #define cOutputPort1Inactive 0x40 // bit b6 | ||
81 | |||
82 | #define cOutputPort2Active 0x00 // bit b7 | ||
83 | #define cOutputPort2Inactive 0x80 // bit b7 | ||
84 | |||
85 | |||
86 | //// second reg (c) | ||
87 | #define cDeemphasisOFF 0x00 // bit c5 | ||
88 | #define cDeemphasisON 0x20 // bit c5 | ||
89 | |||
90 | #define cDeemphasis75 0x00 // bit c6 | ||
91 | #define cDeemphasis50 0x40 // bit c6 | ||
92 | |||
93 | #define cAudioGain0 0x00 // bit c7 | ||
94 | #define cAudioGain6 0x80 // bit c7 | ||
95 | |||
96 | #define cTopMask 0x1f // bit c0:4 | ||
97 | #define cTopDefault 0x10 // bit c0:4 | ||
98 | |||
99 | //// third reg (e) | ||
100 | #define cAudioIF_4_5 0x00 // bit e0:1 | ||
101 | #define cAudioIF_5_5 0x01 // bit e0:1 | ||
102 | #define cAudioIF_6_0 0x02 // bit e0:1 | ||
103 | #define cAudioIF_6_5 0x03 // bit e0:1 | ||
104 | |||
105 | |||
106 | #define cVideoIFMask 0x1c // bit e2:4 | ||
107 | /* Video IF selection in TV Mode (bit B3=0) */ | ||
108 | #define cVideoIF_58_75 0x00 // bit e2:4 | ||
109 | #define cVideoIF_45_75 0x04 // bit e2:4 | ||
110 | #define cVideoIF_38_90 0x08 // bit e2:4 | ||
111 | #define cVideoIF_38_00 0x0C // bit e2:4 | ||
112 | #define cVideoIF_33_90 0x10 // bit e2:4 | ||
113 | #define cVideoIF_33_40 0x14 // bit e2:4 | ||
114 | #define cRadioIF_45_75 0x18 // bit e2:4 | ||
115 | #define cRadioIF_38_90 0x1C // bit e2:4 | ||
116 | |||
117 | /* IF1 selection in Radio Mode (bit B3=1) */ | ||
118 | #define cRadioIF_33_30 0x00 // bit e2,4 (also 0x10,0x14) | ||
119 | #define cRadioIF_41_30 0x04 // bit e2,4 | ||
120 | |||
121 | /* Output of AFC pin in radio mode when bit E7=1 */ | ||
122 | #define cRadioAGC_SIF 0x00 // bit e3 | ||
123 | #define cRadioAGC_FM 0x08 // bit e3 | ||
124 | |||
125 | #define cTunerGainNormal 0x00 // bit e5 | ||
126 | #define cTunerGainLow 0x20 // bit e5 | ||
127 | |||
128 | #define cGating_18 0x00 // bit e6 | ||
129 | #define cGating_36 0x40 // bit e6 | ||
130 | |||
131 | #define cAgcOutON 0x80 // bit e7 | ||
132 | #define cAgcOutOFF 0x00 // bit e7 | ||
133 | |||
134 | /* ---------------------------------------------------------------------- */ | ||
135 | |||
136 | static struct tvnorm tvnorms[] = { | ||
137 | { | ||
138 | .std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H | V4L2_STD_PAL_N, | ||
139 | .name = "PAL-BGHN", | ||
140 | .b = ( cNegativeFmTV | | ||
141 | cQSS ), | ||
142 | .c = ( cDeemphasisON | | ||
143 | cDeemphasis50 | | ||
144 | cTopDefault), | ||
145 | .e = ( cGating_36 | | ||
146 | cAudioIF_5_5 | | ||
147 | cVideoIF_38_90 ), | ||
148 | },{ | ||
149 | .std = V4L2_STD_PAL_I, | ||
150 | .name = "PAL-I", | ||
151 | .b = ( cNegativeFmTV | | ||
152 | cQSS ), | ||
153 | .c = ( cDeemphasisON | | ||
154 | cDeemphasis50 | | ||
155 | cTopDefault), | ||
156 | .e = ( cGating_36 | | ||
157 | cAudioIF_6_0 | | ||
158 | cVideoIF_38_90 ), | ||
159 | },{ | ||
160 | .std = V4L2_STD_PAL_DK, | ||
161 | .name = "PAL-DK", | ||
162 | .b = ( cNegativeFmTV | | ||
163 | cQSS ), | ||
164 | .c = ( cDeemphasisON | | ||
165 | cDeemphasis50 | | ||
166 | cTopDefault), | ||
167 | .e = ( cGating_36 | | ||
168 | cAudioIF_6_5 | | ||
169 | cVideoIF_38_90 ), | ||
170 | },{ | ||
171 | .std = V4L2_STD_PAL_M | V4L2_STD_PAL_Nc, | ||
172 | .name = "PAL-M/Nc", | ||
173 | .b = ( cNegativeFmTV | | ||
174 | cQSS ), | ||
175 | .c = ( cDeemphasisON | | ||
176 | cDeemphasis75 | | ||
177 | cTopDefault), | ||
178 | .e = ( cGating_36 | | ||
179 | cAudioIF_4_5 | | ||
180 | cVideoIF_45_75 ), | ||
181 | },{ | ||
182 | .std = V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, | ||
183 | .name = "SECAM-BGH", | ||
184 | .b = ( cNegativeFmTV | | ||
185 | cQSS ), | ||
186 | .c = ( cTopDefault), | ||
187 | .e = ( cAudioIF_5_5 | | ||
188 | cVideoIF_38_90 ), | ||
189 | },{ | ||
190 | .std = V4L2_STD_SECAM_L, | ||
191 | .name = "SECAM-L", | ||
192 | .b = ( cPositiveAmTV | | ||
193 | cQSS ), | ||
194 | .c = ( cTopDefault), | ||
195 | .e = ( cGating_36 | | ||
196 | cAudioIF_6_5 | | ||
197 | cVideoIF_38_90 ), | ||
198 | },{ | ||
199 | .std = V4L2_STD_SECAM_LC, | ||
200 | .name = "SECAM-L'", | ||
201 | .b = ( cOutputPort2Inactive | | ||
202 | cPositiveAmTV | | ||
203 | cQSS ), | ||
204 | .c = ( cTopDefault), | ||
205 | .e = ( cGating_36 | | ||
206 | cAudioIF_6_5 | | ||
207 | cVideoIF_33_90 ), | ||
208 | },{ | ||
209 | .std = V4L2_STD_SECAM_DK, | ||
210 | .name = "SECAM-DK", | ||
211 | .b = ( cNegativeFmTV | | ||
212 | cQSS ), | ||
213 | .c = ( cDeemphasisON | | ||
214 | cDeemphasis50 | | ||
215 | cTopDefault), | ||
216 | .e = ( cGating_36 | | ||
217 | cAudioIF_6_5 | | ||
218 | cVideoIF_38_90 ), | ||
219 | },{ | ||
220 | .std = V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_KR, | ||
221 | .name = "NTSC-M", | ||
222 | .b = ( cNegativeFmTV | | ||
223 | cQSS ), | ||
224 | .c = ( cDeemphasisON | | ||
225 | cDeemphasis75 | | ||
226 | cTopDefault), | ||
227 | .e = ( cGating_36 | | ||
228 | cAudioIF_4_5 | | ||
229 | cVideoIF_45_75 ), | ||
230 | },{ | ||
231 | .std = V4L2_STD_NTSC_M_JP, | ||
232 | .name = "NTSC-M-JP", | ||
233 | .b = ( cNegativeFmTV | | ||
234 | cQSS ), | ||
235 | .c = ( cDeemphasisON | | ||
236 | cDeemphasis50 | | ||
237 | cTopDefault), | ||
238 | .e = ( cGating_36 | | ||
239 | cAudioIF_4_5 | | ||
240 | cVideoIF_58_75 ), | ||
241 | } | ||
242 | }; | ||
243 | |||
244 | static struct tvnorm radio_stereo = { | ||
245 | .name = "Radio Stereo", | ||
246 | .b = ( cFmRadio | | ||
247 | cQSS ), | ||
248 | .c = ( cDeemphasisOFF | | ||
249 | cAudioGain6 | | ||
250 | cTopDefault), | ||
251 | .e = ( cTunerGainLow | | ||
252 | cAudioIF_5_5 | | ||
253 | cRadioIF_38_90 ), | ||
254 | }; | ||
255 | |||
256 | static struct tvnorm radio_mono = { | ||
257 | .name = "Radio Mono", | ||
258 | .b = ( cFmRadio | | ||
259 | cQSS ), | ||
260 | .c = ( cDeemphasisON | | ||
261 | cDeemphasis75 | | ||
262 | cTopDefault), | ||
263 | .e = ( cTunerGainLow | | ||
264 | cAudioIF_5_5 | | ||
265 | cRadioIF_38_90 ), | ||
266 | }; | ||
267 | |||
268 | /* ---------------------------------------------------------------------- */ | ||
269 | |||
270 | static void dump_read_message(struct dvb_frontend *fe, unsigned char *buf) | ||
271 | { | ||
272 | struct tda9887_priv *priv = fe->analog_demod_priv; | ||
273 | |||
274 | static char *afc[16] = { | ||
275 | "- 12.5 kHz", | ||
276 | "- 37.5 kHz", | ||
277 | "- 62.5 kHz", | ||
278 | "- 87.5 kHz", | ||
279 | "-112.5 kHz", | ||
280 | "-137.5 kHz", | ||
281 | "-162.5 kHz", | ||
282 | "-187.5 kHz [min]", | ||
283 | "+187.5 kHz [max]", | ||
284 | "+162.5 kHz", | ||
285 | "+137.5 kHz", | ||
286 | "+112.5 kHz", | ||
287 | "+ 87.5 kHz", | ||
288 | "+ 62.5 kHz", | ||
289 | "+ 37.5 kHz", | ||
290 | "+ 12.5 kHz", | ||
291 | }; | ||
292 | tuner_info("read: 0x%2x\n", buf[0]); | ||
293 | tuner_info(" after power on : %s\n", (buf[0] & 0x01) ? "yes" : "no"); | ||
294 | tuner_info(" afc : %s\n", afc[(buf[0] >> 1) & 0x0f]); | ||
295 | tuner_info(" fmif level : %s\n", (buf[0] & 0x20) ? "high" : "low"); | ||
296 | tuner_info(" afc window : %s\n", (buf[0] & 0x40) ? "in" : "out"); | ||
297 | tuner_info(" vfi level : %s\n", (buf[0] & 0x80) ? "high" : "low"); | ||
298 | } | ||
299 | |||
300 | static void dump_write_message(struct dvb_frontend *fe, unsigned char *buf) | ||
301 | { | ||
302 | struct tda9887_priv *priv = fe->analog_demod_priv; | ||
303 | |||
304 | static char *sound[4] = { | ||
305 | "AM/TV", | ||
306 | "FM/radio", | ||
307 | "FM/TV", | ||
308 | "FM/radio" | ||
309 | }; | ||
310 | static char *adjust[32] = { | ||
311 | "-16", "-15", "-14", "-13", "-12", "-11", "-10", "-9", | ||
312 | "-8", "-7", "-6", "-5", "-4", "-3", "-2", "-1", | ||
313 | "0", "+1", "+2", "+3", "+4", "+5", "+6", "+7", | ||
314 | "+8", "+9", "+10", "+11", "+12", "+13", "+14", "+15" | ||
315 | }; | ||
316 | static char *deemph[4] = { | ||
317 | "no", "no", "75", "50" | ||
318 | }; | ||
319 | static char *carrier[4] = { | ||
320 | "4.5 MHz", | ||
321 | "5.5 MHz", | ||
322 | "6.0 MHz", | ||
323 | "6.5 MHz / AM" | ||
324 | }; | ||
325 | static char *vif[8] = { | ||
326 | "58.75 MHz", | ||
327 | "45.75 MHz", | ||
328 | "38.9 MHz", | ||
329 | "38.0 MHz", | ||
330 | "33.9 MHz", | ||
331 | "33.4 MHz", | ||
332 | "45.75 MHz + pin13", | ||
333 | "38.9 MHz + pin13", | ||
334 | }; | ||
335 | static char *rif[4] = { | ||
336 | "44 MHz", | ||
337 | "52 MHz", | ||
338 | "52 MHz", | ||
339 | "44 MHz", | ||
340 | }; | ||
341 | |||
342 | tuner_info("write: byte B 0x%02x\n", buf[1]); | ||
343 | tuner_info(" B0 video mode : %s\n", | ||
344 | (buf[1] & 0x01) ? "video trap" : "sound trap"); | ||
345 | tuner_info(" B1 auto mute fm : %s\n", | ||
346 | (buf[1] & 0x02) ? "yes" : "no"); | ||
347 | tuner_info(" B2 carrier mode : %s\n", | ||
348 | (buf[1] & 0x04) ? "QSS" : "Intercarrier"); | ||
349 | tuner_info(" B3-4 tv sound/radio : %s\n", | ||
350 | sound[(buf[1] & 0x18) >> 3]); | ||
351 | tuner_info(" B5 force mute audio: %s\n", | ||
352 | (buf[1] & 0x20) ? "yes" : "no"); | ||
353 | tuner_info(" B6 output port 1 : %s\n", | ||
354 | (buf[1] & 0x40) ? "high (inactive)" : "low (active)"); | ||
355 | tuner_info(" B7 output port 2 : %s\n", | ||
356 | (buf[1] & 0x80) ? "high (inactive)" : "low (active)"); | ||
357 | |||
358 | tuner_info("write: byte C 0x%02x\n", buf[2]); | ||
359 | tuner_info(" C0-4 top adjustment : %s dB\n", | ||
360 | adjust[buf[2] & 0x1f]); | ||
361 | tuner_info(" C5-6 de-emphasis : %s\n", | ||
362 | deemph[(buf[2] & 0x60) >> 5]); | ||
363 | tuner_info(" C7 audio gain : %s\n", | ||
364 | (buf[2] & 0x80) ? "-6" : "0"); | ||
365 | |||
366 | tuner_info("write: byte E 0x%02x\n", buf[3]); | ||
367 | tuner_info(" E0-1 sound carrier : %s\n", | ||
368 | carrier[(buf[3] & 0x03)]); | ||
369 | tuner_info(" E6 l pll gating : %s\n", | ||
370 | (buf[3] & 0x40) ? "36" : "13"); | ||
371 | |||
372 | if (buf[1] & 0x08) { | ||
373 | /* radio */ | ||
374 | tuner_info(" E2-4 video if : %s\n", | ||
375 | rif[(buf[3] & 0x0c) >> 2]); | ||
376 | tuner_info(" E7 vif agc output : %s\n", | ||
377 | (buf[3] & 0x80) | ||
378 | ? ((buf[3] & 0x10) ? "fm-agc radio" : | ||
379 | "sif-agc radio") | ||
380 | : "fm radio carrier afc"); | ||
381 | } else { | ||
382 | /* video */ | ||
383 | tuner_info(" E2-4 video if : %s\n", | ||
384 | vif[(buf[3] & 0x1c) >> 2]); | ||
385 | tuner_info(" E5 tuner gain : %s\n", | ||
386 | (buf[3] & 0x80) | ||
387 | ? ((buf[3] & 0x20) ? "external" : "normal") | ||
388 | : ((buf[3] & 0x20) ? "minimum" : "normal")); | ||
389 | tuner_info(" E7 vif agc output : %s\n", | ||
390 | (buf[3] & 0x80) ? ((buf[3] & 0x20) | ||
391 | ? "pin3 port, pin22 vif agc out" | ||
392 | : "pin22 port, pin3 vif acg ext in") | ||
393 | : "pin3+pin22 port"); | ||
394 | } | ||
395 | tuner_info("--\n"); | ||
396 | } | ||
397 | |||
398 | /* ---------------------------------------------------------------------- */ | ||
399 | |||
400 | static int tda9887_set_tvnorm(struct dvb_frontend *fe) | ||
401 | { | ||
402 | struct tda9887_priv *priv = fe->analog_demod_priv; | ||
403 | struct tvnorm *norm = NULL; | ||
404 | char *buf = priv->data; | ||
405 | int i; | ||
406 | |||
407 | if (priv->mode == V4L2_TUNER_RADIO) { | ||
408 | if (priv->audmode == V4L2_TUNER_MODE_MONO) | ||
409 | norm = &radio_mono; | ||
410 | else | ||
411 | norm = &radio_stereo; | ||
412 | } else { | ||
413 | for (i = 0; i < ARRAY_SIZE(tvnorms); i++) { | ||
414 | if (tvnorms[i].std & priv->std) { | ||
415 | norm = tvnorms+i; | ||
416 | break; | ||
417 | } | ||
418 | } | ||
419 | } | ||
420 | if (NULL == norm) { | ||
421 | tuner_dbg("Unsupported tvnorm entry - audio muted\n"); | ||
422 | return -1; | ||
423 | } | ||
424 | |||
425 | tuner_dbg("configure for: %s\n", norm->name); | ||
426 | buf[1] = norm->b; | ||
427 | buf[2] = norm->c; | ||
428 | buf[3] = norm->e; | ||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | static unsigned int port1 = UNSET; | ||
433 | static unsigned int port2 = UNSET; | ||
434 | static unsigned int qss = UNSET; | ||
435 | static unsigned int adjust = UNSET; | ||
436 | |||
437 | module_param(port1, int, 0644); | ||
438 | module_param(port2, int, 0644); | ||
439 | module_param(qss, int, 0644); | ||
440 | module_param(adjust, int, 0644); | ||
441 | |||
442 | static int tda9887_set_insmod(struct dvb_frontend *fe) | ||
443 | { | ||
444 | struct tda9887_priv *priv = fe->analog_demod_priv; | ||
445 | char *buf = priv->data; | ||
446 | |||
447 | if (UNSET != port1) { | ||
448 | if (port1) | ||
449 | buf[1] |= cOutputPort1Inactive; | ||
450 | else | ||
451 | buf[1] &= ~cOutputPort1Inactive; | ||
452 | } | ||
453 | if (UNSET != port2) { | ||
454 | if (port2) | ||
455 | buf[1] |= cOutputPort2Inactive; | ||
456 | else | ||
457 | buf[1] &= ~cOutputPort2Inactive; | ||
458 | } | ||
459 | |||
460 | if (UNSET != qss) { | ||
461 | if (qss) | ||
462 | buf[1] |= cQSS; | ||
463 | else | ||
464 | buf[1] &= ~cQSS; | ||
465 | } | ||
466 | |||
467 | if (adjust < 0x20) { | ||
468 | buf[2] &= ~cTopMask; | ||
469 | buf[2] |= adjust; | ||
470 | } | ||
471 | return 0; | ||
472 | } | ||
473 | |||
474 | static int tda9887_do_config(struct dvb_frontend *fe) | ||
475 | { | ||
476 | struct tda9887_priv *priv = fe->analog_demod_priv; | ||
477 | char *buf = priv->data; | ||
478 | |||
479 | if (priv->config & TDA9887_PORT1_ACTIVE) | ||
480 | buf[1] &= ~cOutputPort1Inactive; | ||
481 | if (priv->config & TDA9887_PORT1_INACTIVE) | ||
482 | buf[1] |= cOutputPort1Inactive; | ||
483 | if (priv->config & TDA9887_PORT2_ACTIVE) | ||
484 | buf[1] &= ~cOutputPort2Inactive; | ||
485 | if (priv->config & TDA9887_PORT2_INACTIVE) | ||
486 | buf[1] |= cOutputPort2Inactive; | ||
487 | |||
488 | if (priv->config & TDA9887_QSS) | ||
489 | buf[1] |= cQSS; | ||
490 | if (priv->config & TDA9887_INTERCARRIER) | ||
491 | buf[1] &= ~cQSS; | ||
492 | |||
493 | if (priv->config & TDA9887_AUTOMUTE) | ||
494 | buf[1] |= cAutoMuteFmActive; | ||
495 | if (priv->config & TDA9887_DEEMPHASIS_MASK) { | ||
496 | buf[2] &= ~0x60; | ||
497 | switch (priv->config & TDA9887_DEEMPHASIS_MASK) { | ||
498 | case TDA9887_DEEMPHASIS_NONE: | ||
499 | buf[2] |= cDeemphasisOFF; | ||
500 | break; | ||
501 | case TDA9887_DEEMPHASIS_50: | ||
502 | buf[2] |= cDeemphasisON | cDeemphasis50; | ||
503 | break; | ||
504 | case TDA9887_DEEMPHASIS_75: | ||
505 | buf[2] |= cDeemphasisON | cDeemphasis75; | ||
506 | break; | ||
507 | } | ||
508 | } | ||
509 | if (priv->config & TDA9887_TOP_SET) { | ||
510 | buf[2] &= ~cTopMask; | ||
511 | buf[2] |= (priv->config >> 8) & cTopMask; | ||
512 | } | ||
513 | if ((priv->config & TDA9887_INTERCARRIER_NTSC) && | ||
514 | (priv->std & V4L2_STD_NTSC)) | ||
515 | buf[1] &= ~cQSS; | ||
516 | if (priv->config & TDA9887_GATING_18) | ||
517 | buf[3] &= ~cGating_36; | ||
518 | |||
519 | if (priv->mode == V4L2_TUNER_RADIO) { | ||
520 | if (priv->config & TDA9887_RIF_41_3) { | ||
521 | buf[3] &= ~cVideoIFMask; | ||
522 | buf[3] |= cRadioIF_41_30; | ||
523 | } | ||
524 | if (priv->config & TDA9887_GAIN_NORMAL) | ||
525 | buf[3] &= ~cTunerGainLow; | ||
526 | } | ||
527 | |||
528 | return 0; | ||
529 | } | ||
530 | |||
531 | /* ---------------------------------------------------------------------- */ | ||
532 | |||
533 | static int tda9887_status(struct dvb_frontend *fe) | ||
534 | { | ||
535 | struct tda9887_priv *priv = fe->analog_demod_priv; | ||
536 | unsigned char buf[1]; | ||
537 | int rc; | ||
538 | |||
539 | memset(buf,0,sizeof(buf)); | ||
540 | if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,buf,1))) | ||
541 | tuner_info("i2c i/o error: rc == %d (should be 1)\n", rc); | ||
542 | dump_read_message(fe, buf); | ||
543 | return 0; | ||
544 | } | ||
545 | |||
546 | static void tda9887_configure(struct dvb_frontend *fe) | ||
547 | { | ||
548 | struct tda9887_priv *priv = fe->analog_demod_priv; | ||
549 | int rc; | ||
550 | |||
551 | memset(priv->data,0,sizeof(priv->data)); | ||
552 | tda9887_set_tvnorm(fe); | ||
553 | |||
554 | /* A note on the port settings: | ||
555 | These settings tend to depend on the specifics of the board. | ||
556 | By default they are set to inactive (bit value 1) by this driver, | ||
557 | overwriting any changes made by the tvnorm. This means that it | ||
558 | is the responsibility of the module using the tda9887 to set | ||
559 | these values in case of changes in the tvnorm. | ||
560 | In many cases port 2 should be made active (0) when selecting | ||
561 | SECAM-L, and port 2 should remain inactive (1) for SECAM-L'. | ||
562 | |||
563 | For the other standards the tda9887 application note says that | ||
564 | the ports should be set to active (0), but, again, that may | ||
565 | differ depending on the precise hardware configuration. | ||
566 | */ | ||
567 | priv->data[1] |= cOutputPort1Inactive; | ||
568 | priv->data[1] |= cOutputPort2Inactive; | ||
569 | |||
570 | tda9887_do_config(fe); | ||
571 | tda9887_set_insmod(fe); | ||
572 | |||
573 | if (priv->standby) | ||
574 | priv->data[1] |= cForcedMuteAudioON; | ||
575 | |||
576 | tuner_dbg("writing: b=0x%02x c=0x%02x e=0x%02x\n", | ||
577 | priv->data[1], priv->data[2], priv->data[3]); | ||
578 | if (debug > 1) | ||
579 | dump_write_message(fe, priv->data); | ||
580 | |||
581 | if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,priv->data,4))) | ||
582 | tuner_info("i2c i/o error: rc == %d (should be 4)\n", rc); | ||
583 | |||
584 | if (debug > 2) { | ||
585 | msleep_interruptible(1000); | ||
586 | tda9887_status(fe); | ||
587 | } | ||
588 | } | ||
589 | |||
590 | /* ---------------------------------------------------------------------- */ | ||
591 | |||
592 | static void tda9887_tuner_status(struct dvb_frontend *fe) | ||
593 | { | ||
594 | struct tda9887_priv *priv = fe->analog_demod_priv; | ||
595 | tuner_info("Data bytes: b=0x%02x c=0x%02x e=0x%02x\n", | ||
596 | priv->data[1], priv->data[2], priv->data[3]); | ||
597 | } | ||
598 | |||
599 | static int tda9887_get_afc(struct dvb_frontend *fe) | ||
600 | { | ||
601 | struct tda9887_priv *priv = fe->analog_demod_priv; | ||
602 | static int AFC_BITS_2_kHz[] = { | ||
603 | -12500, -37500, -62500, -97500, | ||
604 | -112500, -137500, -162500, -187500, | ||
605 | 187500, 162500, 137500, 112500, | ||
606 | 97500 , 62500, 37500 , 12500 | ||
607 | }; | ||
608 | int afc=0; | ||
609 | __u8 reg = 0; | ||
610 | |||
611 | if (1 == tuner_i2c_xfer_recv(&priv->i2c_props,®,1)) | ||
612 | afc = AFC_BITS_2_kHz[(reg>>1)&0x0f]; | ||
613 | |||
614 | return afc; | ||
615 | } | ||
616 | |||
617 | static void tda9887_standby(struct dvb_frontend *fe) | ||
618 | { | ||
619 | struct tda9887_priv *priv = fe->analog_demod_priv; | ||
620 | |||
621 | priv->standby = true; | ||
622 | |||
623 | tda9887_configure(fe); | ||
624 | } | ||
625 | |||
626 | static void tda9887_set_params(struct dvb_frontend *fe, | ||
627 | struct analog_parameters *params) | ||
628 | { | ||
629 | struct tda9887_priv *priv = fe->analog_demod_priv; | ||
630 | |||
631 | priv->standby = false; | ||
632 | priv->mode = params->mode; | ||
633 | priv->audmode = params->audmode; | ||
634 | priv->std = params->std; | ||
635 | tda9887_configure(fe); | ||
636 | } | ||
637 | |||
638 | static int tda9887_set_config(struct dvb_frontend *fe, void *priv_cfg) | ||
639 | { | ||
640 | struct tda9887_priv *priv = fe->analog_demod_priv; | ||
641 | |||
642 | priv->config = *(unsigned int *)priv_cfg; | ||
643 | tda9887_configure(fe); | ||
644 | |||
645 | return 0; | ||
646 | } | ||
647 | |||
648 | static void tda9887_release(struct dvb_frontend *fe) | ||
649 | { | ||
650 | struct tda9887_priv *priv = fe->analog_demod_priv; | ||
651 | |||
652 | mutex_lock(&tda9887_list_mutex); | ||
653 | |||
654 | if (priv) | ||
655 | hybrid_tuner_release_state(priv); | ||
656 | |||
657 | mutex_unlock(&tda9887_list_mutex); | ||
658 | |||
659 | fe->analog_demod_priv = NULL; | ||
660 | } | ||
661 | |||
662 | static struct analog_demod_ops tda9887_ops = { | ||
663 | .info = { | ||
664 | .name = "tda9887", | ||
665 | }, | ||
666 | .set_params = tda9887_set_params, | ||
667 | .standby = tda9887_standby, | ||
668 | .tuner_status = tda9887_tuner_status, | ||
669 | .get_afc = tda9887_get_afc, | ||
670 | .release = tda9887_release, | ||
671 | .set_config = tda9887_set_config, | ||
672 | }; | ||
673 | |||
674 | struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, | ||
675 | struct i2c_adapter *i2c_adap, | ||
676 | u8 i2c_addr) | ||
677 | { | ||
678 | struct tda9887_priv *priv = NULL; | ||
679 | int instance; | ||
680 | |||
681 | mutex_lock(&tda9887_list_mutex); | ||
682 | |||
683 | instance = hybrid_tuner_request_state(struct tda9887_priv, priv, | ||
684 | hybrid_tuner_instance_list, | ||
685 | i2c_adap, i2c_addr, "tda9887"); | ||
686 | switch (instance) { | ||
687 | case 0: | ||
688 | mutex_unlock(&tda9887_list_mutex); | ||
689 | return NULL; | ||
690 | case 1: | ||
691 | fe->analog_demod_priv = priv; | ||
692 | priv->standby = true; | ||
693 | tuner_info("tda988[5/6/7] found\n"); | ||
694 | break; | ||
695 | default: | ||
696 | fe->analog_demod_priv = priv; | ||
697 | break; | ||
698 | } | ||
699 | |||
700 | mutex_unlock(&tda9887_list_mutex); | ||
701 | |||
702 | memcpy(&fe->ops.analog_ops, &tda9887_ops, | ||
703 | sizeof(struct analog_demod_ops)); | ||
704 | |||
705 | return fe; | ||
706 | } | ||
707 | EXPORT_SYMBOL_GPL(tda9887_attach); | ||
708 | |||
709 | MODULE_LICENSE("GPL"); | ||
710 | |||
711 | /* | ||
712 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
713 | * --------------------------------------------------------------------------- | ||
714 | * Local variables: | ||
715 | * c-basic-offset: 8 | ||
716 | * End: | ||
717 | */ | ||
diff --git a/drivers/media/tuners/tda9887.h b/drivers/media/tuners/tda9887.h new file mode 100644 index 000000000000..acc419e8c4fc --- /dev/null +++ b/drivers/media/tuners/tda9887.h | |||
@@ -0,0 +1,38 @@ | |||
1 | /* | ||
2 | This program is free software; you can redistribute it and/or modify | ||
3 | it under the terms of the GNU General Public License as published by | ||
4 | the Free Software Foundation; either version 2 of the License, or | ||
5 | (at your option) any later version. | ||
6 | |||
7 | This program is distributed in the hope that it will be useful, | ||
8 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | GNU General Public License for more details. | ||
11 | |||
12 | You should have received a copy of the GNU General Public License | ||
13 | along with this program; if not, write to the Free Software | ||
14 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
15 | */ | ||
16 | |||
17 | #ifndef __TDA9887_H__ | ||
18 | #define __TDA9887_H__ | ||
19 | |||
20 | #include <linux/i2c.h> | ||
21 | #include "dvb_frontend.h" | ||
22 | |||
23 | /* ------------------------------------------------------------------------ */ | ||
24 | #if defined(CONFIG_MEDIA_TUNER_TDA9887) || (defined(CONFIG_MEDIA_TUNER_TDA9887_MODULE) && defined(MODULE)) | ||
25 | extern struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, | ||
26 | struct i2c_adapter *i2c_adap, | ||
27 | u8 i2c_addr); | ||
28 | #else | ||
29 | static inline struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe, | ||
30 | struct i2c_adapter *i2c_adap, | ||
31 | u8 i2c_addr) | ||
32 | { | ||
33 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
34 | return NULL; | ||
35 | } | ||
36 | #endif | ||
37 | |||
38 | #endif /* __TDA9887_H__ */ | ||
diff --git a/drivers/media/tuners/tea5761.c b/drivers/media/tuners/tea5761.c new file mode 100644 index 000000000000..bf78cb9fc52c --- /dev/null +++ b/drivers/media/tuners/tea5761.c | |||
@@ -0,0 +1,348 @@ | |||
1 | /* | ||
2 | * For Philips TEA5761 FM Chip | ||
3 | * I2C address is allways 0x20 (0x10 at 7-bit mode). | ||
4 | * | ||
5 | * Copyright (c) 2005-2007 Mauro Carvalho Chehab (mchehab@infradead.org) | ||
6 | * This code is placed under the terms of the GNUv2 General Public License | ||
7 | * | ||
8 | */ | ||
9 | |||
10 | #include <linux/i2c.h> | ||
11 | #include <linux/slab.h> | ||
12 | #include <linux/delay.h> | ||
13 | #include <linux/videodev2.h> | ||
14 | #include <media/tuner.h> | ||
15 | #include "tuner-i2c.h" | ||
16 | #include "tea5761.h" | ||
17 | |||
18 | static int debug; | ||
19 | module_param(debug, int, 0644); | ||
20 | MODULE_PARM_DESC(debug, "enable verbose debug messages"); | ||
21 | |||
22 | struct tea5761_priv { | ||
23 | struct tuner_i2c_props i2c_props; | ||
24 | |||
25 | u32 frequency; | ||
26 | bool standby; | ||
27 | }; | ||
28 | |||
29 | /*****************************************************************************/ | ||
30 | |||
31 | /*************************** | ||
32 | * TEA5761HN I2C registers * | ||
33 | ***************************/ | ||
34 | |||
35 | /* INTREG - Read: bytes 0 and 1 / Write: byte 0 */ | ||
36 | |||
37 | /* first byte for reading */ | ||
38 | #define TEA5761_INTREG_IFFLAG 0x10 | ||
39 | #define TEA5761_INTREG_LEVFLAG 0x8 | ||
40 | #define TEA5761_INTREG_FRRFLAG 0x2 | ||
41 | #define TEA5761_INTREG_BLFLAG 0x1 | ||
42 | |||
43 | /* second byte for reading / byte for writing */ | ||
44 | #define TEA5761_INTREG_IFMSK 0x10 | ||
45 | #define TEA5761_INTREG_LEVMSK 0x8 | ||
46 | #define TEA5761_INTREG_FRMSK 0x2 | ||
47 | #define TEA5761_INTREG_BLMSK 0x1 | ||
48 | |||
49 | /* FRQSET - Read: bytes 2 and 3 / Write: byte 1 and 2 */ | ||
50 | |||
51 | /* First byte */ | ||
52 | #define TEA5761_FRQSET_SEARCH_UP 0x80 /* 1=Station search from botton to up */ | ||
53 | #define TEA5761_FRQSET_SEARCH_MODE 0x40 /* 1=Search mode */ | ||
54 | |||
55 | /* Bits 0-5 for divider MSB */ | ||
56 | |||
57 | /* Second byte */ | ||
58 | /* Bits 0-7 for divider LSB */ | ||
59 | |||
60 | /* TNCTRL - Read: bytes 4 and 5 / Write: Bytes 3 and 4 */ | ||
61 | |||
62 | /* first byte */ | ||
63 | |||
64 | #define TEA5761_TNCTRL_PUPD_0 0x40 /* Power UP/Power Down MSB */ | ||
65 | #define TEA5761_TNCTRL_BLIM 0X20 /* 1= Japan Frequencies, 0= European frequencies */ | ||
66 | #define TEA5761_TNCTRL_SWPM 0x10 /* 1= software port is FRRFLAG */ | ||
67 | #define TEA5761_TNCTRL_IFCTC 0x08 /* 1= IF count time 15.02 ms, 0= IF count time 2.02 ms */ | ||
68 | #define TEA5761_TNCTRL_AFM 0x04 | ||
69 | #define TEA5761_TNCTRL_SMUTE 0x02 /* 1= Soft mute */ | ||
70 | #define TEA5761_TNCTRL_SNC 0x01 | ||
71 | |||
72 | /* second byte */ | ||
73 | |||
74 | #define TEA5761_TNCTRL_MU 0x80 /* 1=Hard mute */ | ||
75 | #define TEA5761_TNCTRL_SSL_1 0x40 | ||
76 | #define TEA5761_TNCTRL_SSL_0 0x20 | ||
77 | #define TEA5761_TNCTRL_HLSI 0x10 | ||
78 | #define TEA5761_TNCTRL_MST 0x08 /* 1 = mono */ | ||
79 | #define TEA5761_TNCTRL_SWP 0x04 | ||
80 | #define TEA5761_TNCTRL_DTC 0x02 /* 1 = deemphasis 50 us, 0 = deemphasis 75 us */ | ||
81 | #define TEA5761_TNCTRL_AHLSI 0x01 | ||
82 | |||
83 | /* FRQCHECK - Read: bytes 6 and 7 */ | ||
84 | /* First byte */ | ||
85 | |||
86 | /* Bits 0-5 for divider MSB */ | ||
87 | |||
88 | /* Second byte */ | ||
89 | /* Bits 0-7 for divider LSB */ | ||
90 | |||
91 | /* TUNCHECK - Read: bytes 8 and 9 */ | ||
92 | |||
93 | /* First byte */ | ||
94 | #define TEA5761_TUNCHECK_IF_MASK 0x7e /* IF count */ | ||
95 | #define TEA5761_TUNCHECK_TUNTO 0x01 | ||
96 | |||
97 | /* Second byte */ | ||
98 | #define TEA5761_TUNCHECK_LEV_MASK 0xf0 /* Level Count */ | ||
99 | #define TEA5761_TUNCHECK_LD 0x08 | ||
100 | #define TEA5761_TUNCHECK_STEREO 0x04 | ||
101 | |||
102 | /* TESTREG - Read: bytes 10 and 11 / Write: bytes 5 and 6 */ | ||
103 | |||
104 | /* All zero = no test mode */ | ||
105 | |||
106 | /* MANID - Read: bytes 12 and 13 */ | ||
107 | |||
108 | /* First byte - should be 0x10 */ | ||
109 | #define TEA5767_MANID_VERSION_MASK 0xf0 /* Version = 1 */ | ||
110 | #define TEA5767_MANID_ID_MSB_MASK 0x0f /* Manufacurer ID - should be 0 */ | ||
111 | |||
112 | /* Second byte - Should be 0x2b */ | ||
113 | |||
114 | #define TEA5767_MANID_ID_LSB_MASK 0xfe /* Manufacturer ID - should be 0x15 */ | ||
115 | #define TEA5767_MANID_IDAV 0x01 /* 1 = Chip has ID, 0 = Chip has no ID */ | ||
116 | |||
117 | /* Chip ID - Read: bytes 14 and 15 */ | ||
118 | |||
119 | /* First byte - should be 0x57 */ | ||
120 | |||
121 | /* Second byte - should be 0x61 */ | ||
122 | |||
123 | /*****************************************************************************/ | ||
124 | |||
125 | #define FREQ_OFFSET 0 /* for TEA5767, it is 700 to give the right freq */ | ||
126 | static void tea5761_status_dump(unsigned char *buffer) | ||
127 | { | ||
128 | unsigned int div, frq; | ||
129 | |||
130 | div = ((buffer[2] & 0x3f) << 8) | buffer[3]; | ||
131 | |||
132 | frq = 1000 * (div * 32768 / 1000 + FREQ_OFFSET + 225) / 4; /* Freq in KHz */ | ||
133 | |||
134 | printk(KERN_INFO "tea5761: Frequency %d.%03d KHz (divider = 0x%04x)\n", | ||
135 | frq / 1000, frq % 1000, div); | ||
136 | } | ||
137 | |||
138 | /* Freq should be specifyed at 62.5 Hz */ | ||
139 | static int __set_radio_freq(struct dvb_frontend *fe, | ||
140 | unsigned int freq, | ||
141 | bool mono) | ||
142 | { | ||
143 | struct tea5761_priv *priv = fe->tuner_priv; | ||
144 | unsigned int frq = freq; | ||
145 | unsigned char buffer[7] = {0, 0, 0, 0, 0, 0, 0 }; | ||
146 | unsigned div; | ||
147 | int rc; | ||
148 | |||
149 | tuner_dbg("radio freq counter %d\n", frq); | ||
150 | |||
151 | if (priv->standby) { | ||
152 | tuner_dbg("TEA5761 set to standby mode\n"); | ||
153 | buffer[5] |= TEA5761_TNCTRL_MU; | ||
154 | } else { | ||
155 | buffer[4] |= TEA5761_TNCTRL_PUPD_0; | ||
156 | } | ||
157 | |||
158 | |||
159 | if (mono) { | ||
160 | tuner_dbg("TEA5761 set to mono\n"); | ||
161 | buffer[5] |= TEA5761_TNCTRL_MST; | ||
162 | } else { | ||
163 | tuner_dbg("TEA5761 set to stereo\n"); | ||
164 | } | ||
165 | |||
166 | div = (1000 * (frq * 4 / 16 + 700 + 225) ) >> 15; | ||
167 | buffer[1] = (div >> 8) & 0x3f; | ||
168 | buffer[2] = div & 0xff; | ||
169 | |||
170 | if (debug) | ||
171 | tea5761_status_dump(buffer); | ||
172 | |||
173 | if (7 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 7))) | ||
174 | tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); | ||
175 | |||
176 | priv->frequency = frq * 125 / 2; | ||
177 | |||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | static int set_radio_freq(struct dvb_frontend *fe, | ||
182 | struct analog_parameters *params) | ||
183 | { | ||
184 | struct tea5761_priv *priv = fe->analog_demod_priv; | ||
185 | |||
186 | priv->standby = false; | ||
187 | |||
188 | return __set_radio_freq(fe, params->frequency, | ||
189 | params->audmode == V4L2_TUNER_MODE_MONO); | ||
190 | } | ||
191 | |||
192 | static int set_radio_sleep(struct dvb_frontend *fe) | ||
193 | { | ||
194 | struct tea5761_priv *priv = fe->analog_demod_priv; | ||
195 | |||
196 | priv->standby = true; | ||
197 | |||
198 | return __set_radio_freq(fe, priv->frequency, false); | ||
199 | } | ||
200 | |||
201 | static int tea5761_read_status(struct dvb_frontend *fe, char *buffer) | ||
202 | { | ||
203 | struct tea5761_priv *priv = fe->tuner_priv; | ||
204 | int rc; | ||
205 | |||
206 | memset(buffer, 0, 16); | ||
207 | if (16 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 16))) { | ||
208 | tuner_warn("i2c i/o error: rc == %d (should be 16)\n", rc); | ||
209 | return -EREMOTEIO; | ||
210 | } | ||
211 | |||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | static inline int tea5761_signal(struct dvb_frontend *fe, const char *buffer) | ||
216 | { | ||
217 | struct tea5761_priv *priv = fe->tuner_priv; | ||
218 | |||
219 | int signal = ((buffer[9] & TEA5761_TUNCHECK_LEV_MASK) << (13 - 4)); | ||
220 | |||
221 | tuner_dbg("Signal strength: %d\n", signal); | ||
222 | |||
223 | return signal; | ||
224 | } | ||
225 | |||
226 | static inline int tea5761_stereo(struct dvb_frontend *fe, const char *buffer) | ||
227 | { | ||
228 | struct tea5761_priv *priv = fe->tuner_priv; | ||
229 | |||
230 | int stereo = buffer[9] & TEA5761_TUNCHECK_STEREO; | ||
231 | |||
232 | tuner_dbg("Radio ST GET = %02x\n", stereo); | ||
233 | |||
234 | return (stereo ? V4L2_TUNER_SUB_STEREO : 0); | ||
235 | } | ||
236 | |||
237 | static int tea5761_get_status(struct dvb_frontend *fe, u32 *status) | ||
238 | { | ||
239 | unsigned char buffer[16]; | ||
240 | |||
241 | *status = 0; | ||
242 | |||
243 | if (0 == tea5761_read_status(fe, buffer)) { | ||
244 | if (tea5761_signal(fe, buffer)) | ||
245 | *status = TUNER_STATUS_LOCKED; | ||
246 | if (tea5761_stereo(fe, buffer)) | ||
247 | *status |= TUNER_STATUS_STEREO; | ||
248 | } | ||
249 | |||
250 | return 0; | ||
251 | } | ||
252 | |||
253 | static int tea5761_get_rf_strength(struct dvb_frontend *fe, u16 *strength) | ||
254 | { | ||
255 | unsigned char buffer[16]; | ||
256 | |||
257 | *strength = 0; | ||
258 | |||
259 | if (0 == tea5761_read_status(fe, buffer)) | ||
260 | *strength = tea5761_signal(fe, buffer); | ||
261 | |||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr) | ||
266 | { | ||
267 | unsigned char buffer[16]; | ||
268 | int rc; | ||
269 | struct tuner_i2c_props i2c = { .adap = i2c_adap, .addr = i2c_addr }; | ||
270 | |||
271 | if (16 != (rc = tuner_i2c_xfer_recv(&i2c, buffer, 16))) { | ||
272 | printk(KERN_WARNING "it is not a TEA5761. Received %i chars.\n", rc); | ||
273 | return -EINVAL; | ||
274 | } | ||
275 | |||
276 | if ((buffer[13] != 0x2b) || (buffer[14] != 0x57) || (buffer[15] != 0x061)) { | ||
277 | printk(KERN_WARNING "Manufacturer ID= 0x%02x, Chip ID = %02x%02x." | ||
278 | " It is not a TEA5761\n", | ||
279 | buffer[13], buffer[14], buffer[15]); | ||
280 | return -EINVAL; | ||
281 | } | ||
282 | printk(KERN_WARNING "tea5761: TEA%02x%02x detected. " | ||
283 | "Manufacturer ID= 0x%02x\n", | ||
284 | buffer[14], buffer[15], buffer[13]); | ||
285 | |||
286 | return 0; | ||
287 | } | ||
288 | |||
289 | static int tea5761_release(struct dvb_frontend *fe) | ||
290 | { | ||
291 | kfree(fe->tuner_priv); | ||
292 | fe->tuner_priv = NULL; | ||
293 | |||
294 | return 0; | ||
295 | } | ||
296 | |||
297 | static int tea5761_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
298 | { | ||
299 | struct tea5761_priv *priv = fe->tuner_priv; | ||
300 | *frequency = priv->frequency; | ||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | static struct dvb_tuner_ops tea5761_tuner_ops = { | ||
305 | .info = { | ||
306 | .name = "tea5761", // Philips TEA5761HN FM Radio | ||
307 | }, | ||
308 | .set_analog_params = set_radio_freq, | ||
309 | .sleep = set_radio_sleep, | ||
310 | .release = tea5761_release, | ||
311 | .get_frequency = tea5761_get_frequency, | ||
312 | .get_status = tea5761_get_status, | ||
313 | .get_rf_strength = tea5761_get_rf_strength, | ||
314 | }; | ||
315 | |||
316 | struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, | ||
317 | struct i2c_adapter* i2c_adap, | ||
318 | u8 i2c_addr) | ||
319 | { | ||
320 | struct tea5761_priv *priv = NULL; | ||
321 | |||
322 | if (tea5761_autodetection(i2c_adap, i2c_addr) != 0) | ||
323 | return NULL; | ||
324 | |||
325 | priv = kzalloc(sizeof(struct tea5761_priv), GFP_KERNEL); | ||
326 | if (priv == NULL) | ||
327 | return NULL; | ||
328 | fe->tuner_priv = priv; | ||
329 | |||
330 | priv->i2c_props.addr = i2c_addr; | ||
331 | priv->i2c_props.adap = i2c_adap; | ||
332 | priv->i2c_props.name = "tea5761"; | ||
333 | |||
334 | memcpy(&fe->ops.tuner_ops, &tea5761_tuner_ops, | ||
335 | sizeof(struct dvb_tuner_ops)); | ||
336 | |||
337 | tuner_info("type set to %s\n", "Philips TEA5761HN FM Radio"); | ||
338 | |||
339 | return fe; | ||
340 | } | ||
341 | |||
342 | |||
343 | EXPORT_SYMBOL_GPL(tea5761_attach); | ||
344 | EXPORT_SYMBOL_GPL(tea5761_autodetection); | ||
345 | |||
346 | MODULE_DESCRIPTION("Philips TEA5761 FM tuner driver"); | ||
347 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); | ||
348 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/tuners/tea5761.h b/drivers/media/tuners/tea5761.h new file mode 100644 index 000000000000..2e2ff82c95a4 --- /dev/null +++ b/drivers/media/tuners/tea5761.h | |||
@@ -0,0 +1,47 @@ | |||
1 | /* | ||
2 | This program is free software; you can redistribute it and/or modify | ||
3 | it under the terms of the GNU General Public License as published by | ||
4 | the Free Software Foundation; either version 2 of the License, or | ||
5 | (at your option) any later version. | ||
6 | |||
7 | This program is distributed in the hope that it will be useful, | ||
8 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | GNU General Public License for more details. | ||
11 | |||
12 | You should have received a copy of the GNU General Public License | ||
13 | along with this program; if not, write to the Free Software | ||
14 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
15 | */ | ||
16 | |||
17 | #ifndef __TEA5761_H__ | ||
18 | #define __TEA5761_H__ | ||
19 | |||
20 | #include <linux/i2c.h> | ||
21 | #include "dvb_frontend.h" | ||
22 | |||
23 | #if defined(CONFIG_MEDIA_TUNER_TEA5761) || (defined(CONFIG_MEDIA_TUNER_TEA5761_MODULE) && defined(MODULE)) | ||
24 | extern int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); | ||
25 | |||
26 | extern struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, | ||
27 | struct i2c_adapter* i2c_adap, | ||
28 | u8 i2c_addr); | ||
29 | #else | ||
30 | static inline int tea5761_autodetection(struct i2c_adapter* i2c_adap, | ||
31 | u8 i2c_addr) | ||
32 | { | ||
33 | printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", | ||
34 | __func__); | ||
35 | return -EINVAL; | ||
36 | } | ||
37 | |||
38 | static inline struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe, | ||
39 | struct i2c_adapter* i2c_adap, | ||
40 | u8 i2c_addr) | ||
41 | { | ||
42 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
43 | return NULL; | ||
44 | } | ||
45 | #endif | ||
46 | |||
47 | #endif /* __TEA5761_H__ */ | ||
diff --git a/drivers/media/tuners/tea5767.c b/drivers/media/tuners/tea5767.c new file mode 100644 index 000000000000..36e85d81acb2 --- /dev/null +++ b/drivers/media/tuners/tea5767.c | |||
@@ -0,0 +1,475 @@ | |||
1 | /* | ||
2 | * For Philips TEA5767 FM Chip used on some TV Cards like Prolink Pixelview | ||
3 | * I2C address is allways 0xC0. | ||
4 | * | ||
5 | * | ||
6 | * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@infradead.org) | ||
7 | * This code is placed under the terms of the GNU General Public License | ||
8 | * | ||
9 | * tea5767 autodetection thanks to Torsten Seeboth and Atsushi Nakagawa | ||
10 | * from their contributions on DScaler. | ||
11 | */ | ||
12 | |||
13 | #include <linux/i2c.h> | ||
14 | #include <linux/slab.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/videodev2.h> | ||
17 | #include "tuner-i2c.h" | ||
18 | #include "tea5767.h" | ||
19 | |||
20 | static int debug; | ||
21 | module_param(debug, int, 0644); | ||
22 | MODULE_PARM_DESC(debug, "enable verbose debug messages"); | ||
23 | |||
24 | /*****************************************************************************/ | ||
25 | |||
26 | struct tea5767_priv { | ||
27 | struct tuner_i2c_props i2c_props; | ||
28 | u32 frequency; | ||
29 | struct tea5767_ctrl ctrl; | ||
30 | }; | ||
31 | |||
32 | /*****************************************************************************/ | ||
33 | |||
34 | /****************************** | ||
35 | * Write mode register values * | ||
36 | ******************************/ | ||
37 | |||
38 | /* First register */ | ||
39 | #define TEA5767_MUTE 0x80 /* Mutes output */ | ||
40 | #define TEA5767_SEARCH 0x40 /* Activates station search */ | ||
41 | /* Bits 0-5 for divider MSB */ | ||
42 | |||
43 | /* Second register */ | ||
44 | /* Bits 0-7 for divider LSB */ | ||
45 | |||
46 | /* Third register */ | ||
47 | |||
48 | /* Station search from botton to up */ | ||
49 | #define TEA5767_SEARCH_UP 0x80 | ||
50 | |||
51 | /* Searches with ADC output = 10 */ | ||
52 | #define TEA5767_SRCH_HIGH_LVL 0x60 | ||
53 | |||
54 | /* Searches with ADC output = 10 */ | ||
55 | #define TEA5767_SRCH_MID_LVL 0x40 | ||
56 | |||
57 | /* Searches with ADC output = 5 */ | ||
58 | #define TEA5767_SRCH_LOW_LVL 0x20 | ||
59 | |||
60 | /* if on, div=4*(Frf+Fif)/Fref otherwise, div=4*(Frf-Fif)/Freq) */ | ||
61 | #define TEA5767_HIGH_LO_INJECT 0x10 | ||
62 | |||
63 | /* Disable stereo */ | ||
64 | #define TEA5767_MONO 0x08 | ||
65 | |||
66 | /* Disable right channel and turns to mono */ | ||
67 | #define TEA5767_MUTE_RIGHT 0x04 | ||
68 | |||
69 | /* Disable left channel and turns to mono */ | ||
70 | #define TEA5767_MUTE_LEFT 0x02 | ||
71 | |||
72 | #define TEA5767_PORT1_HIGH 0x01 | ||
73 | |||
74 | /* Fourth register */ | ||
75 | #define TEA5767_PORT2_HIGH 0x80 | ||
76 | /* Chips stops working. Only I2C bus remains on */ | ||
77 | #define TEA5767_STDBY 0x40 | ||
78 | |||
79 | /* Japan freq (76-108 MHz. If disabled, 87.5-108 MHz */ | ||
80 | #define TEA5767_JAPAN_BAND 0x20 | ||
81 | |||
82 | /* Unselected means 32.768 KHz freq as reference. Otherwise Xtal at 13 MHz */ | ||
83 | #define TEA5767_XTAL_32768 0x10 | ||
84 | |||
85 | /* Cuts weak signals */ | ||
86 | #define TEA5767_SOFT_MUTE 0x08 | ||
87 | |||
88 | /* Activates high cut control */ | ||
89 | #define TEA5767_HIGH_CUT_CTRL 0x04 | ||
90 | |||
91 | /* Activates stereo noise control */ | ||
92 | #define TEA5767_ST_NOISE_CTL 0x02 | ||
93 | |||
94 | /* If activate PORT 1 indicates SEARCH or else it is used as PORT1 */ | ||
95 | #define TEA5767_SRCH_IND 0x01 | ||
96 | |||
97 | /* Fifth register */ | ||
98 | |||
99 | /* By activating, it will use Xtal at 13 MHz as reference for divider */ | ||
100 | #define TEA5767_PLLREF_ENABLE 0x80 | ||
101 | |||
102 | /* By activating, deemphasis=50, or else, deemphasis of 50us */ | ||
103 | #define TEA5767_DEEMPH_75 0X40 | ||
104 | |||
105 | /***************************** | ||
106 | * Read mode register values * | ||
107 | *****************************/ | ||
108 | |||
109 | /* First register */ | ||
110 | #define TEA5767_READY_FLAG_MASK 0x80 | ||
111 | #define TEA5767_BAND_LIMIT_MASK 0X40 | ||
112 | /* Bits 0-5 for divider MSB after search or preset */ | ||
113 | |||
114 | /* Second register */ | ||
115 | /* Bits 0-7 for divider LSB after search or preset */ | ||
116 | |||
117 | /* Third register */ | ||
118 | #define TEA5767_STEREO_MASK 0x80 | ||
119 | #define TEA5767_IF_CNTR_MASK 0x7f | ||
120 | |||
121 | /* Fourth register */ | ||
122 | #define TEA5767_ADC_LEVEL_MASK 0xf0 | ||
123 | |||
124 | /* should be 0 */ | ||
125 | #define TEA5767_CHIP_ID_MASK 0x0f | ||
126 | |||
127 | /* Fifth register */ | ||
128 | /* Reserved for future extensions */ | ||
129 | #define TEA5767_RESERVED_MASK 0xff | ||
130 | |||
131 | /*****************************************************************************/ | ||
132 | |||
133 | static void tea5767_status_dump(struct tea5767_priv *priv, | ||
134 | unsigned char *buffer) | ||
135 | { | ||
136 | unsigned int div, frq; | ||
137 | |||
138 | if (TEA5767_READY_FLAG_MASK & buffer[0]) | ||
139 | tuner_info("Ready Flag ON\n"); | ||
140 | else | ||
141 | tuner_info("Ready Flag OFF\n"); | ||
142 | |||
143 | if (TEA5767_BAND_LIMIT_MASK & buffer[0]) | ||
144 | tuner_info("Tuner at band limit\n"); | ||
145 | else | ||
146 | tuner_info("Tuner not at band limit\n"); | ||
147 | |||
148 | div = ((buffer[0] & 0x3f) << 8) | buffer[1]; | ||
149 | |||
150 | switch (priv->ctrl.xtal_freq) { | ||
151 | case TEA5767_HIGH_LO_13MHz: | ||
152 | frq = (div * 50000 - 700000 - 225000) / 4; /* Freq in KHz */ | ||
153 | break; | ||
154 | case TEA5767_LOW_LO_13MHz: | ||
155 | frq = (div * 50000 + 700000 + 225000) / 4; /* Freq in KHz */ | ||
156 | break; | ||
157 | case TEA5767_LOW_LO_32768: | ||
158 | frq = (div * 32768 + 700000 + 225000) / 4; /* Freq in KHz */ | ||
159 | break; | ||
160 | case TEA5767_HIGH_LO_32768: | ||
161 | default: | ||
162 | frq = (div * 32768 - 700000 - 225000) / 4; /* Freq in KHz */ | ||
163 | break; | ||
164 | } | ||
165 | buffer[0] = (div >> 8) & 0x3f; | ||
166 | buffer[1] = div & 0xff; | ||
167 | |||
168 | tuner_info("Frequency %d.%03d KHz (divider = 0x%04x)\n", | ||
169 | frq / 1000, frq % 1000, div); | ||
170 | |||
171 | if (TEA5767_STEREO_MASK & buffer[2]) | ||
172 | tuner_info("Stereo\n"); | ||
173 | else | ||
174 | tuner_info("Mono\n"); | ||
175 | |||
176 | tuner_info("IF Counter = %d\n", buffer[2] & TEA5767_IF_CNTR_MASK); | ||
177 | |||
178 | tuner_info("ADC Level = %d\n", | ||
179 | (buffer[3] & TEA5767_ADC_LEVEL_MASK) >> 4); | ||
180 | |||
181 | tuner_info("Chip ID = %d\n", (buffer[3] & TEA5767_CHIP_ID_MASK)); | ||
182 | |||
183 | tuner_info("Reserved = 0x%02x\n", | ||
184 | (buffer[4] & TEA5767_RESERVED_MASK)); | ||
185 | } | ||
186 | |||
187 | /* Freq should be specifyed at 62.5 Hz */ | ||
188 | static int set_radio_freq(struct dvb_frontend *fe, | ||
189 | struct analog_parameters *params) | ||
190 | { | ||
191 | struct tea5767_priv *priv = fe->tuner_priv; | ||
192 | unsigned int frq = params->frequency; | ||
193 | unsigned char buffer[5]; | ||
194 | unsigned div; | ||
195 | int rc; | ||
196 | |||
197 | tuner_dbg("radio freq = %d.%03d MHz\n", frq/16000,(frq/16)%1000); | ||
198 | |||
199 | buffer[2] = 0; | ||
200 | |||
201 | if (priv->ctrl.port1) | ||
202 | buffer[2] |= TEA5767_PORT1_HIGH; | ||
203 | |||
204 | if (params->audmode == V4L2_TUNER_MODE_MONO) { | ||
205 | tuner_dbg("TEA5767 set to mono\n"); | ||
206 | buffer[2] |= TEA5767_MONO; | ||
207 | } else { | ||
208 | tuner_dbg("TEA5767 set to stereo\n"); | ||
209 | } | ||
210 | |||
211 | |||
212 | buffer[3] = 0; | ||
213 | |||
214 | if (priv->ctrl.port2) | ||
215 | buffer[3] |= TEA5767_PORT2_HIGH; | ||
216 | |||
217 | if (priv->ctrl.high_cut) | ||
218 | buffer[3] |= TEA5767_HIGH_CUT_CTRL; | ||
219 | |||
220 | if (priv->ctrl.st_noise) | ||
221 | buffer[3] |= TEA5767_ST_NOISE_CTL; | ||
222 | |||
223 | if (priv->ctrl.soft_mute) | ||
224 | buffer[3] |= TEA5767_SOFT_MUTE; | ||
225 | |||
226 | if (priv->ctrl.japan_band) | ||
227 | buffer[3] |= TEA5767_JAPAN_BAND; | ||
228 | |||
229 | buffer[4] = 0; | ||
230 | |||
231 | if (priv->ctrl.deemph_75) | ||
232 | buffer[4] |= TEA5767_DEEMPH_75; | ||
233 | |||
234 | if (priv->ctrl.pllref) | ||
235 | buffer[4] |= TEA5767_PLLREF_ENABLE; | ||
236 | |||
237 | |||
238 | /* Rounds freq to next decimal value - for 62.5 KHz step */ | ||
239 | /* frq = 20*(frq/16)+radio_frq[frq%16]; */ | ||
240 | |||
241 | switch (priv->ctrl.xtal_freq) { | ||
242 | case TEA5767_HIGH_LO_13MHz: | ||
243 | tuner_dbg("radio HIGH LO inject xtal @ 13 MHz\n"); | ||
244 | buffer[2] |= TEA5767_HIGH_LO_INJECT; | ||
245 | div = (frq * (4000 / 16) + 700000 + 225000 + 25000) / 50000; | ||
246 | break; | ||
247 | case TEA5767_LOW_LO_13MHz: | ||
248 | tuner_dbg("radio LOW LO inject xtal @ 13 MHz\n"); | ||
249 | |||
250 | div = (frq * (4000 / 16) - 700000 - 225000 + 25000) / 50000; | ||
251 | break; | ||
252 | case TEA5767_LOW_LO_32768: | ||
253 | tuner_dbg("radio LOW LO inject xtal @ 32,768 MHz\n"); | ||
254 | buffer[3] |= TEA5767_XTAL_32768; | ||
255 | /* const 700=4000*175 Khz - to adjust freq to right value */ | ||
256 | div = ((frq * (4000 / 16) - 700000 - 225000) + 16384) >> 15; | ||
257 | break; | ||
258 | case TEA5767_HIGH_LO_32768: | ||
259 | default: | ||
260 | tuner_dbg("radio HIGH LO inject xtal @ 32,768 MHz\n"); | ||
261 | |||
262 | buffer[2] |= TEA5767_HIGH_LO_INJECT; | ||
263 | buffer[3] |= TEA5767_XTAL_32768; | ||
264 | div = ((frq * (4000 / 16) + 700000 + 225000) + 16384) >> 15; | ||
265 | break; | ||
266 | } | ||
267 | buffer[0] = (div >> 8) & 0x3f; | ||
268 | buffer[1] = div & 0xff; | ||
269 | |||
270 | if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5))) | ||
271 | tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); | ||
272 | |||
273 | if (debug) { | ||
274 | if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) | ||
275 | tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); | ||
276 | else | ||
277 | tea5767_status_dump(priv, buffer); | ||
278 | } | ||
279 | |||
280 | priv->frequency = frq * 125 / 2; | ||
281 | |||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | static int tea5767_read_status(struct dvb_frontend *fe, char *buffer) | ||
286 | { | ||
287 | struct tea5767_priv *priv = fe->tuner_priv; | ||
288 | int rc; | ||
289 | |||
290 | memset(buffer, 0, 5); | ||
291 | if (5 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props, buffer, 5))) { | ||
292 | tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); | ||
293 | return -EREMOTEIO; | ||
294 | } | ||
295 | |||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | static inline int tea5767_signal(struct dvb_frontend *fe, const char *buffer) | ||
300 | { | ||
301 | struct tea5767_priv *priv = fe->tuner_priv; | ||
302 | |||
303 | int signal = ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << 8); | ||
304 | |||
305 | tuner_dbg("Signal strength: %d\n", signal); | ||
306 | |||
307 | return signal; | ||
308 | } | ||
309 | |||
310 | static inline int tea5767_stereo(struct dvb_frontend *fe, const char *buffer) | ||
311 | { | ||
312 | struct tea5767_priv *priv = fe->tuner_priv; | ||
313 | |||
314 | int stereo = buffer[2] & TEA5767_STEREO_MASK; | ||
315 | |||
316 | tuner_dbg("Radio ST GET = %02x\n", stereo); | ||
317 | |||
318 | return (stereo ? V4L2_TUNER_SUB_STEREO : 0); | ||
319 | } | ||
320 | |||
321 | static int tea5767_get_status(struct dvb_frontend *fe, u32 *status) | ||
322 | { | ||
323 | unsigned char buffer[5]; | ||
324 | |||
325 | *status = 0; | ||
326 | |||
327 | if (0 == tea5767_read_status(fe, buffer)) { | ||
328 | if (tea5767_signal(fe, buffer)) | ||
329 | *status = TUNER_STATUS_LOCKED; | ||
330 | if (tea5767_stereo(fe, buffer)) | ||
331 | *status |= TUNER_STATUS_STEREO; | ||
332 | } | ||
333 | |||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | static int tea5767_get_rf_strength(struct dvb_frontend *fe, u16 *strength) | ||
338 | { | ||
339 | unsigned char buffer[5]; | ||
340 | |||
341 | *strength = 0; | ||
342 | |||
343 | if (0 == tea5767_read_status(fe, buffer)) | ||
344 | *strength = tea5767_signal(fe, buffer); | ||
345 | |||
346 | return 0; | ||
347 | } | ||
348 | |||
349 | static int tea5767_standby(struct dvb_frontend *fe) | ||
350 | { | ||
351 | unsigned char buffer[5]; | ||
352 | struct tea5767_priv *priv = fe->tuner_priv; | ||
353 | unsigned div, rc; | ||
354 | |||
355 | div = (87500 * 4 + 700 + 225 + 25) / 50; /* Set frequency to 87.5 MHz */ | ||
356 | buffer[0] = (div >> 8) & 0x3f; | ||
357 | buffer[1] = div & 0xff; | ||
358 | buffer[2] = TEA5767_PORT1_HIGH; | ||
359 | buffer[3] = TEA5767_PORT2_HIGH | TEA5767_HIGH_CUT_CTRL | | ||
360 | TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND | TEA5767_STDBY; | ||
361 | buffer[4] = 0; | ||
362 | |||
363 | if (5 != (rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 5))) | ||
364 | tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc); | ||
365 | |||
366 | return 0; | ||
367 | } | ||
368 | |||
369 | int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr) | ||
370 | { | ||
371 | struct tuner_i2c_props i2c = { .adap = i2c_adap, .addr = i2c_addr }; | ||
372 | unsigned char buffer[7] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | ||
373 | int rc; | ||
374 | |||
375 | if ((rc = tuner_i2c_xfer_recv(&i2c, buffer, 7))< 5) { | ||
376 | printk(KERN_WARNING "It is not a TEA5767. Received %i bytes.\n", rc); | ||
377 | return -EINVAL; | ||
378 | } | ||
379 | |||
380 | /* If all bytes are the same then it's a TV tuner and not a tea5767 */ | ||
381 | if (buffer[0] == buffer[1] && buffer[0] == buffer[2] && | ||
382 | buffer[0] == buffer[3] && buffer[0] == buffer[4]) { | ||
383 | printk(KERN_WARNING "All bytes are equal. It is not a TEA5767\n"); | ||
384 | return -EINVAL; | ||
385 | } | ||
386 | |||
387 | /* Status bytes: | ||
388 | * Byte 4: bit 3:1 : CI (Chip Identification) == 0 | ||
389 | * bit 0 : internally set to 0 | ||
390 | * Byte 5: bit 7:0 : == 0 | ||
391 | */ | ||
392 | if (((buffer[3] & 0x0f) != 0x00) || (buffer[4] != 0x00)) { | ||
393 | printk(KERN_WARNING "Chip ID is not zero. It is not a TEA5767\n"); | ||
394 | return -EINVAL; | ||
395 | } | ||
396 | |||
397 | |||
398 | return 0; | ||
399 | } | ||
400 | |||
401 | static int tea5767_release(struct dvb_frontend *fe) | ||
402 | { | ||
403 | kfree(fe->tuner_priv); | ||
404 | fe->tuner_priv = NULL; | ||
405 | |||
406 | return 0; | ||
407 | } | ||
408 | |||
409 | static int tea5767_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
410 | { | ||
411 | struct tea5767_priv *priv = fe->tuner_priv; | ||
412 | *frequency = priv->frequency; | ||
413 | |||
414 | return 0; | ||
415 | } | ||
416 | |||
417 | static int tea5767_set_config (struct dvb_frontend *fe, void *priv_cfg) | ||
418 | { | ||
419 | struct tea5767_priv *priv = fe->tuner_priv; | ||
420 | |||
421 | memcpy(&priv->ctrl, priv_cfg, sizeof(priv->ctrl)); | ||
422 | |||
423 | return 0; | ||
424 | } | ||
425 | |||
426 | static struct dvb_tuner_ops tea5767_tuner_ops = { | ||
427 | .info = { | ||
428 | .name = "tea5767", // Philips TEA5767HN FM Radio | ||
429 | }, | ||
430 | |||
431 | .set_analog_params = set_radio_freq, | ||
432 | .set_config = tea5767_set_config, | ||
433 | .sleep = tea5767_standby, | ||
434 | .release = tea5767_release, | ||
435 | .get_frequency = tea5767_get_frequency, | ||
436 | .get_status = tea5767_get_status, | ||
437 | .get_rf_strength = tea5767_get_rf_strength, | ||
438 | }; | ||
439 | |||
440 | struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, | ||
441 | struct i2c_adapter* i2c_adap, | ||
442 | u8 i2c_addr) | ||
443 | { | ||
444 | struct tea5767_priv *priv = NULL; | ||
445 | |||
446 | priv = kzalloc(sizeof(struct tea5767_priv), GFP_KERNEL); | ||
447 | if (priv == NULL) | ||
448 | return NULL; | ||
449 | fe->tuner_priv = priv; | ||
450 | |||
451 | priv->i2c_props.addr = i2c_addr; | ||
452 | priv->i2c_props.adap = i2c_adap; | ||
453 | priv->i2c_props.name = "tea5767"; | ||
454 | |||
455 | priv->ctrl.xtal_freq = TEA5767_HIGH_LO_32768; | ||
456 | priv->ctrl.port1 = 1; | ||
457 | priv->ctrl.port2 = 1; | ||
458 | priv->ctrl.high_cut = 1; | ||
459 | priv->ctrl.st_noise = 1; | ||
460 | priv->ctrl.japan_band = 1; | ||
461 | |||
462 | memcpy(&fe->ops.tuner_ops, &tea5767_tuner_ops, | ||
463 | sizeof(struct dvb_tuner_ops)); | ||
464 | |||
465 | tuner_info("type set to %s\n", "Philips TEA5767HN FM Radio"); | ||
466 | |||
467 | return fe; | ||
468 | } | ||
469 | |||
470 | EXPORT_SYMBOL_GPL(tea5767_attach); | ||
471 | EXPORT_SYMBOL_GPL(tea5767_autodetection); | ||
472 | |||
473 | MODULE_DESCRIPTION("Philips TEA5767 FM tuner driver"); | ||
474 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); | ||
475 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/tuners/tea5767.h b/drivers/media/tuners/tea5767.h new file mode 100644 index 000000000000..d30ab1b483de --- /dev/null +++ b/drivers/media/tuners/tea5767.h | |||
@@ -0,0 +1,66 @@ | |||
1 | /* | ||
2 | This program is free software; you can redistribute it and/or modify | ||
3 | it under the terms of the GNU General Public License as published by | ||
4 | the Free Software Foundation; either version 2 of the License, or | ||
5 | (at your option) any later version. | ||
6 | |||
7 | This program is distributed in the hope that it will be useful, | ||
8 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | GNU General Public License for more details. | ||
11 | |||
12 | You should have received a copy of the GNU General Public License | ||
13 | along with this program; if not, write to the Free Software | ||
14 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
15 | */ | ||
16 | |||
17 | #ifndef __TEA5767_H__ | ||
18 | #define __TEA5767_H__ | ||
19 | |||
20 | #include <linux/i2c.h> | ||
21 | #include "dvb_frontend.h" | ||
22 | |||
23 | enum tea5767_xtal { | ||
24 | TEA5767_LOW_LO_32768 = 0, | ||
25 | TEA5767_HIGH_LO_32768 = 1, | ||
26 | TEA5767_LOW_LO_13MHz = 2, | ||
27 | TEA5767_HIGH_LO_13MHz = 3, | ||
28 | }; | ||
29 | |||
30 | struct tea5767_ctrl { | ||
31 | unsigned int port1:1; | ||
32 | unsigned int port2:1; | ||
33 | unsigned int high_cut:1; | ||
34 | unsigned int st_noise:1; | ||
35 | unsigned int soft_mute:1; | ||
36 | unsigned int japan_band:1; | ||
37 | unsigned int deemph_75:1; | ||
38 | unsigned int pllref:1; | ||
39 | enum tea5767_xtal xtal_freq; | ||
40 | }; | ||
41 | |||
42 | #if defined(CONFIG_MEDIA_TUNER_TEA5767) || (defined(CONFIG_MEDIA_TUNER_TEA5767_MODULE) && defined(MODULE)) | ||
43 | extern int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr); | ||
44 | |||
45 | extern struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, | ||
46 | struct i2c_adapter* i2c_adap, | ||
47 | u8 i2c_addr); | ||
48 | #else | ||
49 | static inline int tea5767_autodetection(struct i2c_adapter* i2c_adap, | ||
50 | u8 i2c_addr) | ||
51 | { | ||
52 | printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", | ||
53 | __func__); | ||
54 | return -EINVAL; | ||
55 | } | ||
56 | |||
57 | static inline struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe, | ||
58 | struct i2c_adapter* i2c_adap, | ||
59 | u8 i2c_addr) | ||
60 | { | ||
61 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
62 | return NULL; | ||
63 | } | ||
64 | #endif | ||
65 | |||
66 | #endif /* __TEA5767_H__ */ | ||
diff --git a/drivers/media/tuners/tua9001.c b/drivers/media/tuners/tua9001.c new file mode 100644 index 000000000000..de2607084672 --- /dev/null +++ b/drivers/media/tuners/tua9001.c | |||
@@ -0,0 +1,215 @@ | |||
1 | /* | ||
2 | * Infineon TUA 9001 silicon tuner driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Antti Palosaari <crope@iki.fi> | ||
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 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #include "tua9001.h" | ||
22 | #include "tua9001_priv.h" | ||
23 | |||
24 | /* write register */ | ||
25 | static int tua9001_wr_reg(struct tua9001_priv *priv, u8 reg, u16 val) | ||
26 | { | ||
27 | int ret; | ||
28 | u8 buf[3] = { reg, (val >> 8) & 0xff, (val >> 0) & 0xff }; | ||
29 | struct i2c_msg msg[1] = { | ||
30 | { | ||
31 | .addr = priv->cfg->i2c_addr, | ||
32 | .flags = 0, | ||
33 | .len = sizeof(buf), | ||
34 | .buf = buf, | ||
35 | } | ||
36 | }; | ||
37 | |||
38 | ret = i2c_transfer(priv->i2c, msg, 1); | ||
39 | if (ret == 1) { | ||
40 | ret = 0; | ||
41 | } else { | ||
42 | printk(KERN_WARNING "%s: I2C wr failed=%d reg=%02x\n", | ||
43 | __func__, ret, reg); | ||
44 | ret = -EREMOTEIO; | ||
45 | } | ||
46 | |||
47 | return ret; | ||
48 | } | ||
49 | |||
50 | static int tua9001_release(struct dvb_frontend *fe) | ||
51 | { | ||
52 | kfree(fe->tuner_priv); | ||
53 | fe->tuner_priv = NULL; | ||
54 | |||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | static int tua9001_init(struct dvb_frontend *fe) | ||
59 | { | ||
60 | struct tua9001_priv *priv = fe->tuner_priv; | ||
61 | int ret = 0; | ||
62 | u8 i; | ||
63 | struct reg_val data[] = { | ||
64 | { 0x1e, 0x6512 }, | ||
65 | { 0x25, 0xb888 }, | ||
66 | { 0x39, 0x5460 }, | ||
67 | { 0x3b, 0x00c0 }, | ||
68 | { 0x3a, 0xf000 }, | ||
69 | { 0x08, 0x0000 }, | ||
70 | { 0x32, 0x0030 }, | ||
71 | { 0x41, 0x703a }, | ||
72 | { 0x40, 0x1c78 }, | ||
73 | { 0x2c, 0x1c00 }, | ||
74 | { 0x36, 0xc013 }, | ||
75 | { 0x37, 0x6f18 }, | ||
76 | { 0x27, 0x0008 }, | ||
77 | { 0x2a, 0x0001 }, | ||
78 | { 0x34, 0x0a40 }, | ||
79 | }; | ||
80 | |||
81 | if (fe->ops.i2c_gate_ctrl) | ||
82 | fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c-gate */ | ||
83 | |||
84 | for (i = 0; i < ARRAY_SIZE(data); i++) { | ||
85 | ret = tua9001_wr_reg(priv, data[i].reg, data[i].val); | ||
86 | if (ret) | ||
87 | break; | ||
88 | } | ||
89 | |||
90 | if (fe->ops.i2c_gate_ctrl) | ||
91 | fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c-gate */ | ||
92 | |||
93 | if (ret < 0) | ||
94 | pr_debug("%s: failed=%d\n", __func__, ret); | ||
95 | |||
96 | return ret; | ||
97 | } | ||
98 | |||
99 | static int tua9001_set_params(struct dvb_frontend *fe) | ||
100 | { | ||
101 | struct tua9001_priv *priv = fe->tuner_priv; | ||
102 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
103 | int ret, i; | ||
104 | u16 val; | ||
105 | u32 frequency; | ||
106 | struct reg_val data[2]; | ||
107 | |||
108 | pr_debug("%s: delivery_system=%d frequency=%d bandwidth_hz=%d\n", | ||
109 | __func__, c->delivery_system, c->frequency, | ||
110 | c->bandwidth_hz); | ||
111 | |||
112 | switch (c->delivery_system) { | ||
113 | case SYS_DVBT: | ||
114 | switch (c->bandwidth_hz) { | ||
115 | case 8000000: | ||
116 | val = 0x0000; | ||
117 | break; | ||
118 | case 7000000: | ||
119 | val = 0x1000; | ||
120 | break; | ||
121 | case 6000000: | ||
122 | val = 0x2000; | ||
123 | break; | ||
124 | case 5000000: | ||
125 | val = 0x3000; | ||
126 | break; | ||
127 | default: | ||
128 | ret = -EINVAL; | ||
129 | goto err; | ||
130 | } | ||
131 | break; | ||
132 | default: | ||
133 | ret = -EINVAL; | ||
134 | goto err; | ||
135 | } | ||
136 | |||
137 | data[0].reg = 0x04; | ||
138 | data[0].val = val; | ||
139 | |||
140 | frequency = (c->frequency - 150000000); | ||
141 | frequency /= 100; | ||
142 | frequency *= 48; | ||
143 | frequency /= 10000; | ||
144 | |||
145 | data[1].reg = 0x1f; | ||
146 | data[1].val = frequency; | ||
147 | |||
148 | if (fe->ops.i2c_gate_ctrl) | ||
149 | fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c-gate */ | ||
150 | |||
151 | for (i = 0; i < ARRAY_SIZE(data); i++) { | ||
152 | ret = tua9001_wr_reg(priv, data[i].reg, data[i].val); | ||
153 | if (ret < 0) | ||
154 | break; | ||
155 | } | ||
156 | |||
157 | if (fe->ops.i2c_gate_ctrl) | ||
158 | fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c-gate */ | ||
159 | |||
160 | err: | ||
161 | if (ret < 0) | ||
162 | pr_debug("%s: failed=%d\n", __func__, ret); | ||
163 | |||
164 | return ret; | ||
165 | } | ||
166 | |||
167 | static int tua9001_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
168 | { | ||
169 | *frequency = 0; /* Zero-IF */ | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | static const struct dvb_tuner_ops tua9001_tuner_ops = { | ||
175 | .info = { | ||
176 | .name = "Infineon TUA 9001", | ||
177 | |||
178 | .frequency_min = 170000000, | ||
179 | .frequency_max = 862000000, | ||
180 | .frequency_step = 0, | ||
181 | }, | ||
182 | |||
183 | .release = tua9001_release, | ||
184 | |||
185 | .init = tua9001_init, | ||
186 | .set_params = tua9001_set_params, | ||
187 | |||
188 | .get_if_frequency = tua9001_get_if_frequency, | ||
189 | }; | ||
190 | |||
191 | struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe, | ||
192 | struct i2c_adapter *i2c, struct tua9001_config *cfg) | ||
193 | { | ||
194 | struct tua9001_priv *priv = NULL; | ||
195 | |||
196 | priv = kzalloc(sizeof(struct tua9001_priv), GFP_KERNEL); | ||
197 | if (priv == NULL) | ||
198 | return NULL; | ||
199 | |||
200 | priv->cfg = cfg; | ||
201 | priv->i2c = i2c; | ||
202 | |||
203 | printk(KERN_INFO "Infineon TUA 9001 successfully attached."); | ||
204 | |||
205 | memcpy(&fe->ops.tuner_ops, &tua9001_tuner_ops, | ||
206 | sizeof(struct dvb_tuner_ops)); | ||
207 | |||
208 | fe->tuner_priv = priv; | ||
209 | return fe; | ||
210 | } | ||
211 | EXPORT_SYMBOL(tua9001_attach); | ||
212 | |||
213 | MODULE_DESCRIPTION("Infineon TUA 9001 silicon tuner driver"); | ||
214 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | ||
215 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/tuners/tua9001.h b/drivers/media/tuners/tua9001.h new file mode 100644 index 000000000000..38d6ae76b1d6 --- /dev/null +++ b/drivers/media/tuners/tua9001.h | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | * Infineon TUA 9001 silicon tuner driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Antti Palosaari <crope@iki.fi> | ||
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 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef TUA9001_H | ||
22 | #define TUA9001_H | ||
23 | |||
24 | #include "dvb_frontend.h" | ||
25 | |||
26 | struct tua9001_config { | ||
27 | /* | ||
28 | * I2C address | ||
29 | */ | ||
30 | u8 i2c_addr; | ||
31 | }; | ||
32 | |||
33 | #if defined(CONFIG_MEDIA_TUNER_TUA9001) || \ | ||
34 | (defined(CONFIG_MEDIA_TUNER_TUA9001_MODULE) && defined(MODULE)) | ||
35 | extern struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe, | ||
36 | struct i2c_adapter *i2c, struct tua9001_config *cfg); | ||
37 | #else | ||
38 | static inline struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe, | ||
39 | struct i2c_adapter *i2c, struct tua9001_config *cfg) | ||
40 | { | ||
41 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
42 | return NULL; | ||
43 | } | ||
44 | #endif | ||
45 | |||
46 | #endif | ||
diff --git a/drivers/media/tuners/tua9001_priv.h b/drivers/media/tuners/tua9001_priv.h new file mode 100644 index 000000000000..73cc1ce0575c --- /dev/null +++ b/drivers/media/tuners/tua9001_priv.h | |||
@@ -0,0 +1,34 @@ | |||
1 | /* | ||
2 | * Infineon TUA 9001 silicon tuner driver | ||
3 | * | ||
4 | * Copyright (C) 2009 Antti Palosaari <crope@iki.fi> | ||
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 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License along | ||
17 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef TUA9001_PRIV_H | ||
22 | #define TUA9001_PRIV_H | ||
23 | |||
24 | struct reg_val { | ||
25 | u8 reg; | ||
26 | u16 val; | ||
27 | }; | ||
28 | |||
29 | struct tua9001_priv { | ||
30 | struct tua9001_config *cfg; | ||
31 | struct i2c_adapter *i2c; | ||
32 | }; | ||
33 | |||
34 | #endif | ||
diff --git a/drivers/media/tuners/tuner-i2c.h b/drivers/media/tuners/tuner-i2c.h new file mode 100644 index 000000000000..18f005634c67 --- /dev/null +++ b/drivers/media/tuners/tuner-i2c.h | |||
@@ -0,0 +1,182 @@ | |||
1 | /* | ||
2 | tuner-i2c.h - i2c interface for different tuners | ||
3 | |||
4 | Copyright (C) 2007 Michael Krufky (mkrufky@linuxtv.org) | ||
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 | GNU General Public License for more details. | ||
15 | |||
16 | You should have received a copy of the GNU General Public License | ||
17 | along with this program; if not, write to the Free Software | ||
18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | |||
21 | #ifndef __TUNER_I2C_H__ | ||
22 | #define __TUNER_I2C_H__ | ||
23 | |||
24 | #include <linux/i2c.h> | ||
25 | #include <linux/slab.h> | ||
26 | |||
27 | struct tuner_i2c_props { | ||
28 | u8 addr; | ||
29 | struct i2c_adapter *adap; | ||
30 | |||
31 | /* used for tuner instance management */ | ||
32 | int count; | ||
33 | char *name; | ||
34 | }; | ||
35 | |||
36 | static inline int tuner_i2c_xfer_send(struct tuner_i2c_props *props, char *buf, int len) | ||
37 | { | ||
38 | struct i2c_msg msg = { .addr = props->addr, .flags = 0, | ||
39 | .buf = buf, .len = len }; | ||
40 | int ret = i2c_transfer(props->adap, &msg, 1); | ||
41 | |||
42 | return (ret == 1) ? len : ret; | ||
43 | } | ||
44 | |||
45 | static inline int tuner_i2c_xfer_recv(struct tuner_i2c_props *props, char *buf, int len) | ||
46 | { | ||
47 | struct i2c_msg msg = { .addr = props->addr, .flags = I2C_M_RD, | ||
48 | .buf = buf, .len = len }; | ||
49 | int ret = i2c_transfer(props->adap, &msg, 1); | ||
50 | |||
51 | return (ret == 1) ? len : ret; | ||
52 | } | ||
53 | |||
54 | static inline int tuner_i2c_xfer_send_recv(struct tuner_i2c_props *props, | ||
55 | char *obuf, int olen, | ||
56 | char *ibuf, int ilen) | ||
57 | { | ||
58 | struct i2c_msg msg[2] = { { .addr = props->addr, .flags = 0, | ||
59 | .buf = obuf, .len = olen }, | ||
60 | { .addr = props->addr, .flags = I2C_M_RD, | ||
61 | .buf = ibuf, .len = ilen } }; | ||
62 | int ret = i2c_transfer(props->adap, msg, 2); | ||
63 | |||
64 | return (ret == 2) ? ilen : ret; | ||
65 | } | ||
66 | |||
67 | /* Callers must declare as a global for the module: | ||
68 | * | ||
69 | * static LIST_HEAD(hybrid_tuner_instance_list); | ||
70 | * | ||
71 | * hybrid_tuner_instance_list should be the third argument | ||
72 | * passed into hybrid_tuner_request_state(). | ||
73 | * | ||
74 | * state structure must contain the following: | ||
75 | * | ||
76 | * struct list_head hybrid_tuner_instance_list; | ||
77 | * struct tuner_i2c_props i2c_props; | ||
78 | * | ||
79 | * hybrid_tuner_instance_list (both within state structure and globally) | ||
80 | * is only required if the driver is using hybrid_tuner_request_state | ||
81 | * and hybrid_tuner_release_state to manage state sharing between | ||
82 | * multiple instances of hybrid tuners. | ||
83 | */ | ||
84 | |||
85 | #define tuner_printk(kernlvl, i2cprops, fmt, arg...) do { \ | ||
86 | printk(kernlvl "%s %d-%04x: " fmt, i2cprops.name, \ | ||
87 | i2cprops.adap ? \ | ||
88 | i2c_adapter_id(i2cprops.adap) : -1, \ | ||
89 | i2cprops.addr, ##arg); \ | ||
90 | } while (0) | ||
91 | |||
92 | /* TO DO: convert all callers of these macros to pass in | ||
93 | * struct tuner_i2c_props, then remove the macro wrappers */ | ||
94 | |||
95 | #define __tuner_warn(i2cprops, fmt, arg...) do { \ | ||
96 | tuner_printk(KERN_WARNING, i2cprops, fmt, ##arg); \ | ||
97 | } while (0) | ||
98 | |||
99 | #define __tuner_info(i2cprops, fmt, arg...) do { \ | ||
100 | tuner_printk(KERN_INFO, i2cprops, fmt, ##arg); \ | ||
101 | } while (0) | ||
102 | |||
103 | #define __tuner_err(i2cprops, fmt, arg...) do { \ | ||
104 | tuner_printk(KERN_ERR, i2cprops, fmt, ##arg); \ | ||
105 | } while (0) | ||
106 | |||
107 | #define __tuner_dbg(i2cprops, fmt, arg...) do { \ | ||
108 | if ((debug)) \ | ||
109 | tuner_printk(KERN_DEBUG, i2cprops, fmt, ##arg); \ | ||
110 | } while (0) | ||
111 | |||
112 | #define tuner_warn(fmt, arg...) __tuner_warn(priv->i2c_props, fmt, ##arg) | ||
113 | #define tuner_info(fmt, arg...) __tuner_info(priv->i2c_props, fmt, ##arg) | ||
114 | #define tuner_err(fmt, arg...) __tuner_err(priv->i2c_props, fmt, ##arg) | ||
115 | #define tuner_dbg(fmt, arg...) __tuner_dbg(priv->i2c_props, fmt, ##arg) | ||
116 | |||
117 | /****************************************************************************/ | ||
118 | |||
119 | /* The return value of hybrid_tuner_request_state indicates the number of | ||
120 | * instances using this tuner object. | ||
121 | * | ||
122 | * 0 - no instances, indicates an error - kzalloc must have failed | ||
123 | * | ||
124 | * 1 - one instance, indicates that the tuner object was created successfully | ||
125 | * | ||
126 | * 2 (or more) instances, indicates that an existing tuner object was found | ||
127 | */ | ||
128 | |||
129 | #define hybrid_tuner_request_state(type, state, list, i2cadap, i2caddr, devname)\ | ||
130 | ({ \ | ||
131 | int __ret = 0; \ | ||
132 | list_for_each_entry(state, &list, hybrid_tuner_instance_list) { \ | ||
133 | if (((i2cadap) && (state->i2c_props.adap)) && \ | ||
134 | ((i2c_adapter_id(state->i2c_props.adap) == \ | ||
135 | i2c_adapter_id(i2cadap)) && \ | ||
136 | (i2caddr == state->i2c_props.addr))) { \ | ||
137 | __tuner_info(state->i2c_props, \ | ||
138 | "attaching existing instance\n"); \ | ||
139 | state->i2c_props.count++; \ | ||
140 | __ret = state->i2c_props.count; \ | ||
141 | break; \ | ||
142 | } \ | ||
143 | } \ | ||
144 | if (0 == __ret) { \ | ||
145 | state = kzalloc(sizeof(type), GFP_KERNEL); \ | ||
146 | if (NULL == state) \ | ||
147 | goto __fail; \ | ||
148 | state->i2c_props.addr = i2caddr; \ | ||
149 | state->i2c_props.adap = i2cadap; \ | ||
150 | state->i2c_props.name = devname; \ | ||
151 | __tuner_info(state->i2c_props, \ | ||
152 | "creating new instance\n"); \ | ||
153 | list_add_tail(&state->hybrid_tuner_instance_list, &list);\ | ||
154 | state->i2c_props.count++; \ | ||
155 | __ret = state->i2c_props.count; \ | ||
156 | } \ | ||
157 | __fail: \ | ||
158 | __ret; \ | ||
159 | }) | ||
160 | |||
161 | #define hybrid_tuner_release_state(state) \ | ||
162 | ({ \ | ||
163 | int __ret; \ | ||
164 | state->i2c_props.count--; \ | ||
165 | __ret = state->i2c_props.count; \ | ||
166 | if (!state->i2c_props.count) { \ | ||
167 | __tuner_info(state->i2c_props, "destroying instance\n");\ | ||
168 | list_del(&state->hybrid_tuner_instance_list); \ | ||
169 | kfree(state); \ | ||
170 | } \ | ||
171 | __ret; \ | ||
172 | }) | ||
173 | |||
174 | #define hybrid_tuner_report_instance_count(state) \ | ||
175 | ({ \ | ||
176 | int __ret = 0; \ | ||
177 | if (state) \ | ||
178 | __ret = state->i2c_props.count; \ | ||
179 | __ret; \ | ||
180 | }) | ||
181 | |||
182 | #endif /* __TUNER_I2C_H__ */ | ||
diff --git a/drivers/media/tuners/tuner-simple.c b/drivers/media/tuners/tuner-simple.c new file mode 100644 index 000000000000..39e7e583c8c0 --- /dev/null +++ b/drivers/media/tuners/tuner-simple.c | |||
@@ -0,0 +1,1155 @@ | |||
1 | /* | ||
2 | * i2c tv tuner chip device driver | ||
3 | * controls all those simple 4-control-bytes style tuners. | ||
4 | * | ||
5 | * This "tuner-simple" module was split apart from the original "tuner" module. | ||
6 | */ | ||
7 | #include <linux/delay.h> | ||
8 | #include <linux/i2c.h> | ||
9 | #include <linux/videodev2.h> | ||
10 | #include <media/tuner.h> | ||
11 | #include <media/v4l2-common.h> | ||
12 | #include <media/tuner-types.h> | ||
13 | #include "tuner-i2c.h" | ||
14 | #include "tuner-simple.h" | ||
15 | |||
16 | static int debug; | ||
17 | module_param(debug, int, 0644); | ||
18 | MODULE_PARM_DESC(debug, "enable verbose debug messages"); | ||
19 | |||
20 | #define TUNER_SIMPLE_MAX 64 | ||
21 | static unsigned int simple_devcount; | ||
22 | |||
23 | static int offset; | ||
24 | module_param(offset, int, 0664); | ||
25 | MODULE_PARM_DESC(offset, "Allows to specify an offset for tuner"); | ||
26 | |||
27 | static unsigned int atv_input[TUNER_SIMPLE_MAX] = \ | ||
28 | { [0 ... (TUNER_SIMPLE_MAX-1)] = 0 }; | ||
29 | static unsigned int dtv_input[TUNER_SIMPLE_MAX] = \ | ||
30 | { [0 ... (TUNER_SIMPLE_MAX-1)] = 0 }; | ||
31 | module_param_array(atv_input, int, NULL, 0644); | ||
32 | module_param_array(dtv_input, int, NULL, 0644); | ||
33 | MODULE_PARM_DESC(atv_input, "specify atv rf input, 0 for autoselect"); | ||
34 | MODULE_PARM_DESC(dtv_input, "specify dtv rf input, 0 for autoselect"); | ||
35 | |||
36 | /* ---------------------------------------------------------------------- */ | ||
37 | |||
38 | /* tv standard selection for Temic 4046 FM5 | ||
39 | this value takes the low bits of control byte 2 | ||
40 | from datasheet Rev.01, Feb.00 | ||
41 | standard BG I L L2 D | ||
42 | picture IF 38.9 38.9 38.9 33.95 38.9 | ||
43 | sound 1 33.4 32.9 32.4 40.45 32.4 | ||
44 | sound 2 33.16 | ||
45 | NICAM 33.05 32.348 33.05 33.05 | ||
46 | */ | ||
47 | #define TEMIC_SET_PAL_I 0x05 | ||
48 | #define TEMIC_SET_PAL_DK 0x09 | ||
49 | #define TEMIC_SET_PAL_L 0x0a /* SECAM ? */ | ||
50 | #define TEMIC_SET_PAL_L2 0x0b /* change IF ! */ | ||
51 | #define TEMIC_SET_PAL_BG 0x0c | ||
52 | |||
53 | /* tv tuner system standard selection for Philips FQ1216ME | ||
54 | this value takes the low bits of control byte 2 | ||
55 | from datasheet "1999 Nov 16" (supersedes "1999 Mar 23") | ||
56 | standard BG DK I L L` | ||
57 | picture carrier 38.90 38.90 38.90 38.90 33.95 | ||
58 | colour 34.47 34.47 34.47 34.47 38.38 | ||
59 | sound 1 33.40 32.40 32.90 32.40 40.45 | ||
60 | sound 2 33.16 - - - - | ||
61 | NICAM 33.05 33.05 32.35 33.05 39.80 | ||
62 | */ | ||
63 | #define PHILIPS_SET_PAL_I 0x01 /* Bit 2 always zero !*/ | ||
64 | #define PHILIPS_SET_PAL_BGDK 0x09 | ||
65 | #define PHILIPS_SET_PAL_L2 0x0a | ||
66 | #define PHILIPS_SET_PAL_L 0x0b | ||
67 | |||
68 | /* system switching for Philips FI1216MF MK2 | ||
69 | from datasheet "1996 Jul 09", | ||
70 | standard BG L L' | ||
71 | picture carrier 38.90 38.90 33.95 | ||
72 | colour 34.47 34.37 38.38 | ||
73 | sound 1 33.40 32.40 40.45 | ||
74 | sound 2 33.16 - - | ||
75 | NICAM 33.05 33.05 39.80 | ||
76 | */ | ||
77 | #define PHILIPS_MF_SET_STD_BG 0x01 /* Bit 2 must be zero, Bit 3 is system output */ | ||
78 | #define PHILIPS_MF_SET_STD_L 0x03 /* Used on Secam France */ | ||
79 | #define PHILIPS_MF_SET_STD_LC 0x02 /* Used on SECAM L' */ | ||
80 | |||
81 | /* Control byte */ | ||
82 | |||
83 | #define TUNER_RATIO_MASK 0x06 /* Bit cb1:cb2 */ | ||
84 | #define TUNER_RATIO_SELECT_50 0x00 | ||
85 | #define TUNER_RATIO_SELECT_32 0x02 | ||
86 | #define TUNER_RATIO_SELECT_166 0x04 | ||
87 | #define TUNER_RATIO_SELECT_62 0x06 | ||
88 | |||
89 | #define TUNER_CHARGE_PUMP 0x40 /* Bit cb6 */ | ||
90 | |||
91 | /* Status byte */ | ||
92 | |||
93 | #define TUNER_POR 0x80 | ||
94 | #define TUNER_FL 0x40 | ||
95 | #define TUNER_MODE 0x38 | ||
96 | #define TUNER_AFC 0x07 | ||
97 | #define TUNER_SIGNAL 0x07 | ||
98 | #define TUNER_STEREO 0x10 | ||
99 | |||
100 | #define TUNER_PLL_LOCKED 0x40 | ||
101 | #define TUNER_STEREO_MK3 0x04 | ||
102 | |||
103 | static DEFINE_MUTEX(tuner_simple_list_mutex); | ||
104 | static LIST_HEAD(hybrid_tuner_instance_list); | ||
105 | |||
106 | struct tuner_simple_priv { | ||
107 | unsigned int nr; | ||
108 | u16 last_div; | ||
109 | |||
110 | struct tuner_i2c_props i2c_props; | ||
111 | struct list_head hybrid_tuner_instance_list; | ||
112 | |||
113 | unsigned int type; | ||
114 | struct tunertype *tun; | ||
115 | |||
116 | u32 frequency; | ||
117 | u32 bandwidth; | ||
118 | }; | ||
119 | |||
120 | /* ---------------------------------------------------------------------- */ | ||
121 | |||
122 | static int tuner_read_status(struct dvb_frontend *fe) | ||
123 | { | ||
124 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
125 | unsigned char byte; | ||
126 | |||
127 | if (1 != tuner_i2c_xfer_recv(&priv->i2c_props, &byte, 1)) | ||
128 | return 0; | ||
129 | |||
130 | return byte; | ||
131 | } | ||
132 | |||
133 | static inline int tuner_signal(const int status) | ||
134 | { | ||
135 | return (status & TUNER_SIGNAL) << 13; | ||
136 | } | ||
137 | |||
138 | static inline int tuner_stereo(const int type, const int status) | ||
139 | { | ||
140 | switch (type) { | ||
141 | case TUNER_PHILIPS_FM1216ME_MK3: | ||
142 | case TUNER_PHILIPS_FM1236_MK3: | ||
143 | case TUNER_PHILIPS_FM1256_IH3: | ||
144 | case TUNER_LG_NTSC_TAPE: | ||
145 | case TUNER_TCL_MF02GIP_5N: | ||
146 | return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3); | ||
147 | case TUNER_PHILIPS_FM1216MK5: | ||
148 | return status | TUNER_STEREO; | ||
149 | default: | ||
150 | return status & TUNER_STEREO; | ||
151 | } | ||
152 | } | ||
153 | |||
154 | static inline int tuner_islocked(const int status) | ||
155 | { | ||
156 | return (status & TUNER_FL); | ||
157 | } | ||
158 | |||
159 | static inline int tuner_afcstatus(const int status) | ||
160 | { | ||
161 | return (status & TUNER_AFC) - 2; | ||
162 | } | ||
163 | |||
164 | |||
165 | static int simple_get_status(struct dvb_frontend *fe, u32 *status) | ||
166 | { | ||
167 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
168 | int tuner_status; | ||
169 | |||
170 | if (priv->i2c_props.adap == NULL) | ||
171 | return -EINVAL; | ||
172 | |||
173 | tuner_status = tuner_read_status(fe); | ||
174 | |||
175 | *status = 0; | ||
176 | |||
177 | if (tuner_islocked(tuner_status)) | ||
178 | *status = TUNER_STATUS_LOCKED; | ||
179 | if (tuner_stereo(priv->type, tuner_status)) | ||
180 | *status |= TUNER_STATUS_STEREO; | ||
181 | |||
182 | tuner_dbg("AFC Status: %d\n", tuner_afcstatus(tuner_status)); | ||
183 | |||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | static int simple_get_rf_strength(struct dvb_frontend *fe, u16 *strength) | ||
188 | { | ||
189 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
190 | int signal; | ||
191 | |||
192 | if (priv->i2c_props.adap == NULL) | ||
193 | return -EINVAL; | ||
194 | |||
195 | signal = tuner_signal(tuner_read_status(fe)); | ||
196 | |||
197 | *strength = signal; | ||
198 | |||
199 | tuner_dbg("Signal strength: %d\n", signal); | ||
200 | |||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | /* ---------------------------------------------------------------------- */ | ||
205 | |||
206 | static inline char *tuner_param_name(enum param_type type) | ||
207 | { | ||
208 | char *name; | ||
209 | |||
210 | switch (type) { | ||
211 | case TUNER_PARAM_TYPE_RADIO: | ||
212 | name = "radio"; | ||
213 | break; | ||
214 | case TUNER_PARAM_TYPE_PAL: | ||
215 | name = "pal"; | ||
216 | break; | ||
217 | case TUNER_PARAM_TYPE_SECAM: | ||
218 | name = "secam"; | ||
219 | break; | ||
220 | case TUNER_PARAM_TYPE_NTSC: | ||
221 | name = "ntsc"; | ||
222 | break; | ||
223 | case TUNER_PARAM_TYPE_DIGITAL: | ||
224 | name = "digital"; | ||
225 | break; | ||
226 | default: | ||
227 | name = "unknown"; | ||
228 | break; | ||
229 | } | ||
230 | return name; | ||
231 | } | ||
232 | |||
233 | static struct tuner_params *simple_tuner_params(struct dvb_frontend *fe, | ||
234 | enum param_type desired_type) | ||
235 | { | ||
236 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
237 | struct tunertype *tun = priv->tun; | ||
238 | int i; | ||
239 | |||
240 | for (i = 0; i < tun->count; i++) | ||
241 | if (desired_type == tun->params[i].type) | ||
242 | break; | ||
243 | |||
244 | /* use default tuner params if desired_type not available */ | ||
245 | if (i == tun->count) { | ||
246 | tuner_dbg("desired params (%s) undefined for tuner %d\n", | ||
247 | tuner_param_name(desired_type), priv->type); | ||
248 | i = 0; | ||
249 | } | ||
250 | |||
251 | tuner_dbg("using tuner params #%d (%s)\n", i, | ||
252 | tuner_param_name(tun->params[i].type)); | ||
253 | |||
254 | return &tun->params[i]; | ||
255 | } | ||
256 | |||
257 | static int simple_config_lookup(struct dvb_frontend *fe, | ||
258 | struct tuner_params *t_params, | ||
259 | unsigned *frequency, u8 *config, u8 *cb) | ||
260 | { | ||
261 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
262 | int i; | ||
263 | |||
264 | for (i = 0; i < t_params->count; i++) { | ||
265 | if (*frequency > t_params->ranges[i].limit) | ||
266 | continue; | ||
267 | break; | ||
268 | } | ||
269 | if (i == t_params->count) { | ||
270 | tuner_dbg("frequency out of range (%d > %d)\n", | ||
271 | *frequency, t_params->ranges[i - 1].limit); | ||
272 | *frequency = t_params->ranges[--i].limit; | ||
273 | } | ||
274 | *config = t_params->ranges[i].config; | ||
275 | *cb = t_params->ranges[i].cb; | ||
276 | |||
277 | tuner_dbg("freq = %d.%02d (%d), range = %d, " | ||
278 | "config = 0x%02x, cb = 0x%02x\n", | ||
279 | *frequency / 16, *frequency % 16 * 100 / 16, *frequency, | ||
280 | i, *config, *cb); | ||
281 | |||
282 | return i; | ||
283 | } | ||
284 | |||
285 | /* ---------------------------------------------------------------------- */ | ||
286 | |||
287 | static void simple_set_rf_input(struct dvb_frontend *fe, | ||
288 | u8 *config, u8 *cb, unsigned int rf) | ||
289 | { | ||
290 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
291 | |||
292 | switch (priv->type) { | ||
293 | case TUNER_PHILIPS_TUV1236D: | ||
294 | switch (rf) { | ||
295 | case 1: | ||
296 | *cb |= 0x08; | ||
297 | break; | ||
298 | default: | ||
299 | *cb &= ~0x08; | ||
300 | break; | ||
301 | } | ||
302 | break; | ||
303 | case TUNER_PHILIPS_FCV1236D: | ||
304 | switch (rf) { | ||
305 | case 1: | ||
306 | *cb |= 0x01; | ||
307 | break; | ||
308 | default: | ||
309 | *cb &= ~0x01; | ||
310 | break; | ||
311 | } | ||
312 | break; | ||
313 | default: | ||
314 | break; | ||
315 | } | ||
316 | } | ||
317 | |||
318 | static int simple_std_setup(struct dvb_frontend *fe, | ||
319 | struct analog_parameters *params, | ||
320 | u8 *config, u8 *cb) | ||
321 | { | ||
322 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
323 | int rc; | ||
324 | |||
325 | /* tv norm specific stuff for multi-norm tuners */ | ||
326 | switch (priv->type) { | ||
327 | case TUNER_PHILIPS_SECAM: /* FI1216MF */ | ||
328 | /* 0x01 -> ??? no change ??? */ | ||
329 | /* 0x02 -> PAL BDGHI / SECAM L */ | ||
330 | /* 0x04 -> ??? PAL others / SECAM others ??? */ | ||
331 | *cb &= ~0x03; | ||
332 | if (params->std & V4L2_STD_SECAM_L) | ||
333 | /* also valid for V4L2_STD_SECAM */ | ||
334 | *cb |= PHILIPS_MF_SET_STD_L; | ||
335 | else if (params->std & V4L2_STD_SECAM_LC) | ||
336 | *cb |= PHILIPS_MF_SET_STD_LC; | ||
337 | else /* V4L2_STD_B|V4L2_STD_GH */ | ||
338 | *cb |= PHILIPS_MF_SET_STD_BG; | ||
339 | break; | ||
340 | |||
341 | case TUNER_TEMIC_4046FM5: | ||
342 | *cb &= ~0x0f; | ||
343 | |||
344 | if (params->std & V4L2_STD_PAL_BG) { | ||
345 | *cb |= TEMIC_SET_PAL_BG; | ||
346 | |||
347 | } else if (params->std & V4L2_STD_PAL_I) { | ||
348 | *cb |= TEMIC_SET_PAL_I; | ||
349 | |||
350 | } else if (params->std & V4L2_STD_PAL_DK) { | ||
351 | *cb |= TEMIC_SET_PAL_DK; | ||
352 | |||
353 | } else if (params->std & V4L2_STD_SECAM_L) { | ||
354 | *cb |= TEMIC_SET_PAL_L; | ||
355 | |||
356 | } | ||
357 | break; | ||
358 | |||
359 | case TUNER_PHILIPS_FQ1216ME: | ||
360 | *cb &= ~0x0f; | ||
361 | |||
362 | if (params->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) { | ||
363 | *cb |= PHILIPS_SET_PAL_BGDK; | ||
364 | |||
365 | } else if (params->std & V4L2_STD_PAL_I) { | ||
366 | *cb |= PHILIPS_SET_PAL_I; | ||
367 | |||
368 | } else if (params->std & V4L2_STD_SECAM_L) { | ||
369 | *cb |= PHILIPS_SET_PAL_L; | ||
370 | |||
371 | } | ||
372 | break; | ||
373 | |||
374 | case TUNER_PHILIPS_FCV1236D: | ||
375 | /* 0x00 -> ATSC antenna input 1 */ | ||
376 | /* 0x01 -> ATSC antenna input 2 */ | ||
377 | /* 0x02 -> NTSC antenna input 1 */ | ||
378 | /* 0x03 -> NTSC antenna input 2 */ | ||
379 | *cb &= ~0x03; | ||
380 | if (!(params->std & V4L2_STD_ATSC)) | ||
381 | *cb |= 2; | ||
382 | break; | ||
383 | |||
384 | case TUNER_MICROTUNE_4042FI5: | ||
385 | /* Set the charge pump for fast tuning */ | ||
386 | *config |= TUNER_CHARGE_PUMP; | ||
387 | break; | ||
388 | |||
389 | case TUNER_PHILIPS_TUV1236D: | ||
390 | { | ||
391 | struct tuner_i2c_props i2c = priv->i2c_props; | ||
392 | /* 0x40 -> ATSC antenna input 1 */ | ||
393 | /* 0x48 -> ATSC antenna input 2 */ | ||
394 | /* 0x00 -> NTSC antenna input 1 */ | ||
395 | /* 0x08 -> NTSC antenna input 2 */ | ||
396 | u8 buffer[4] = { 0x14, 0x00, 0x17, 0x00}; | ||
397 | *cb &= ~0x40; | ||
398 | if (params->std & V4L2_STD_ATSC) { | ||
399 | *cb |= 0x40; | ||
400 | buffer[1] = 0x04; | ||
401 | } | ||
402 | /* set to the correct mode (analog or digital) */ | ||
403 | i2c.addr = 0x0a; | ||
404 | rc = tuner_i2c_xfer_send(&i2c, &buffer[0], 2); | ||
405 | if (2 != rc) | ||
406 | tuner_warn("i2c i/o error: rc == %d " | ||
407 | "(should be 2)\n", rc); | ||
408 | rc = tuner_i2c_xfer_send(&i2c, &buffer[2], 2); | ||
409 | if (2 != rc) | ||
410 | tuner_warn("i2c i/o error: rc == %d " | ||
411 | "(should be 2)\n", rc); | ||
412 | break; | ||
413 | } | ||
414 | } | ||
415 | if (atv_input[priv->nr]) | ||
416 | simple_set_rf_input(fe, config, cb, atv_input[priv->nr]); | ||
417 | |||
418 | return 0; | ||
419 | } | ||
420 | |||
421 | static int simple_set_aux_byte(struct dvb_frontend *fe, u8 config, u8 aux) | ||
422 | { | ||
423 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
424 | int rc; | ||
425 | u8 buffer[2]; | ||
426 | |||
427 | buffer[0] = (config & ~0x38) | 0x18; | ||
428 | buffer[1] = aux; | ||
429 | |||
430 | tuner_dbg("setting aux byte: 0x%02x 0x%02x\n", buffer[0], buffer[1]); | ||
431 | |||
432 | rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 2); | ||
433 | if (2 != rc) | ||
434 | tuner_warn("i2c i/o error: rc == %d (should be 2)\n", rc); | ||
435 | |||
436 | return rc == 2 ? 0 : rc; | ||
437 | } | ||
438 | |||
439 | static int simple_post_tune(struct dvb_frontend *fe, u8 *buffer, | ||
440 | u16 div, u8 config, u8 cb) | ||
441 | { | ||
442 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
443 | int rc; | ||
444 | |||
445 | switch (priv->type) { | ||
446 | case TUNER_LG_TDVS_H06XF: | ||
447 | simple_set_aux_byte(fe, config, 0x20); | ||
448 | break; | ||
449 | case TUNER_PHILIPS_FQ1216LME_MK3: | ||
450 | simple_set_aux_byte(fe, config, 0x60); /* External AGC */ | ||
451 | break; | ||
452 | case TUNER_MICROTUNE_4042FI5: | ||
453 | { | ||
454 | /* FIXME - this may also work for other tuners */ | ||
455 | unsigned long timeout = jiffies + msecs_to_jiffies(1); | ||
456 | u8 status_byte = 0; | ||
457 | |||
458 | /* Wait until the PLL locks */ | ||
459 | for (;;) { | ||
460 | if (time_after(jiffies, timeout)) | ||
461 | return 0; | ||
462 | rc = tuner_i2c_xfer_recv(&priv->i2c_props, | ||
463 | &status_byte, 1); | ||
464 | if (1 != rc) { | ||
465 | tuner_warn("i2c i/o read error: rc == %d " | ||
466 | "(should be 1)\n", rc); | ||
467 | break; | ||
468 | } | ||
469 | if (status_byte & TUNER_PLL_LOCKED) | ||
470 | break; | ||
471 | udelay(10); | ||
472 | } | ||
473 | |||
474 | /* Set the charge pump for optimized phase noise figure */ | ||
475 | config &= ~TUNER_CHARGE_PUMP; | ||
476 | buffer[0] = (div>>8) & 0x7f; | ||
477 | buffer[1] = div & 0xff; | ||
478 | buffer[2] = config; | ||
479 | buffer[3] = cb; | ||
480 | tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n", | ||
481 | buffer[0], buffer[1], buffer[2], buffer[3]); | ||
482 | |||
483 | rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4); | ||
484 | if (4 != rc) | ||
485 | tuner_warn("i2c i/o error: rc == %d " | ||
486 | "(should be 4)\n", rc); | ||
487 | break; | ||
488 | } | ||
489 | } | ||
490 | |||
491 | return 0; | ||
492 | } | ||
493 | |||
494 | static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer) | ||
495 | { | ||
496 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
497 | |||
498 | switch (priv->type) { | ||
499 | case TUNER_TENA_9533_DI: | ||
500 | case TUNER_YMEC_TVF_5533MF: | ||
501 | tuner_dbg("This tuner doesn't have FM. " | ||
502 | "Most cards have a TEA5767 for FM\n"); | ||
503 | return 0; | ||
504 | case TUNER_PHILIPS_FM1216ME_MK3: | ||
505 | case TUNER_PHILIPS_FM1236_MK3: | ||
506 | case TUNER_PHILIPS_FMD1216ME_MK3: | ||
507 | case TUNER_PHILIPS_FMD1216MEX_MK3: | ||
508 | case TUNER_LG_NTSC_TAPE: | ||
509 | case TUNER_PHILIPS_FM1256_IH3: | ||
510 | case TUNER_TCL_MF02GIP_5N: | ||
511 | buffer[3] = 0x19; | ||
512 | break; | ||
513 | case TUNER_PHILIPS_FM1216MK5: | ||
514 | buffer[2] = 0x88; | ||
515 | buffer[3] = 0x09; | ||
516 | break; | ||
517 | case TUNER_TNF_5335MF: | ||
518 | buffer[3] = 0x11; | ||
519 | break; | ||
520 | case TUNER_LG_PAL_FM: | ||
521 | buffer[3] = 0xa5; | ||
522 | break; | ||
523 | case TUNER_THOMSON_DTT761X: | ||
524 | buffer[3] = 0x39; | ||
525 | break; | ||
526 | case TUNER_PHILIPS_FQ1216LME_MK3: | ||
527 | case TUNER_PHILIPS_FQ1236_MK5: | ||
528 | tuner_err("This tuner doesn't have FM\n"); | ||
529 | /* Set the low band for sanity, since it covers 88-108 MHz */ | ||
530 | buffer[3] = 0x01; | ||
531 | break; | ||
532 | case TUNER_MICROTUNE_4049FM5: | ||
533 | default: | ||
534 | buffer[3] = 0xa4; | ||
535 | break; | ||
536 | } | ||
537 | |||
538 | return 0; | ||
539 | } | ||
540 | |||
541 | /* ---------------------------------------------------------------------- */ | ||
542 | |||
543 | static int simple_set_tv_freq(struct dvb_frontend *fe, | ||
544 | struct analog_parameters *params) | ||
545 | { | ||
546 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
547 | u8 config, cb; | ||
548 | u16 div; | ||
549 | u8 buffer[4]; | ||
550 | int rc, IFPCoff, i; | ||
551 | enum param_type desired_type; | ||
552 | struct tuner_params *t_params; | ||
553 | |||
554 | /* IFPCoff = Video Intermediate Frequency - Vif: | ||
555 | 940 =16*58.75 NTSC/J (Japan) | ||
556 | 732 =16*45.75 M/N STD | ||
557 | 704 =16*44 ATSC (at DVB code) | ||
558 | 632 =16*39.50 I U.K. | ||
559 | 622.4=16*38.90 B/G D/K I, L STD | ||
560 | 592 =16*37.00 D China | ||
561 | 590 =16.36.875 B Australia | ||
562 | 543.2=16*33.95 L' STD | ||
563 | 171.2=16*10.70 FM Radio (at set_radio_freq) | ||
564 | */ | ||
565 | |||
566 | if (params->std == V4L2_STD_NTSC_M_JP) { | ||
567 | IFPCoff = 940; | ||
568 | desired_type = TUNER_PARAM_TYPE_NTSC; | ||
569 | } else if ((params->std & V4L2_STD_MN) && | ||
570 | !(params->std & ~V4L2_STD_MN)) { | ||
571 | IFPCoff = 732; | ||
572 | desired_type = TUNER_PARAM_TYPE_NTSC; | ||
573 | } else if (params->std == V4L2_STD_SECAM_LC) { | ||
574 | IFPCoff = 543; | ||
575 | desired_type = TUNER_PARAM_TYPE_SECAM; | ||
576 | } else { | ||
577 | IFPCoff = 623; | ||
578 | desired_type = TUNER_PARAM_TYPE_PAL; | ||
579 | } | ||
580 | |||
581 | t_params = simple_tuner_params(fe, desired_type); | ||
582 | |||
583 | i = simple_config_lookup(fe, t_params, ¶ms->frequency, | ||
584 | &config, &cb); | ||
585 | |||
586 | div = params->frequency + IFPCoff + offset; | ||
587 | |||
588 | tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, " | ||
589 | "Offset=%d.%02d MHz, div=%0d\n", | ||
590 | params->frequency / 16, params->frequency % 16 * 100 / 16, | ||
591 | IFPCoff / 16, IFPCoff % 16 * 100 / 16, | ||
592 | offset / 16, offset % 16 * 100 / 16, div); | ||
593 | |||
594 | /* tv norm specific stuff for multi-norm tuners */ | ||
595 | simple_std_setup(fe, params, &config, &cb); | ||
596 | |||
597 | if (t_params->cb_first_if_lower_freq && div < priv->last_div) { | ||
598 | buffer[0] = config; | ||
599 | buffer[1] = cb; | ||
600 | buffer[2] = (div>>8) & 0x7f; | ||
601 | buffer[3] = div & 0xff; | ||
602 | } else { | ||
603 | buffer[0] = (div>>8) & 0x7f; | ||
604 | buffer[1] = div & 0xff; | ||
605 | buffer[2] = config; | ||
606 | buffer[3] = cb; | ||
607 | } | ||
608 | priv->last_div = div; | ||
609 | if (t_params->has_tda9887) { | ||
610 | struct v4l2_priv_tun_config tda9887_cfg; | ||
611 | int tda_config = 0; | ||
612 | int is_secam_l = (params->std & (V4L2_STD_SECAM_L | | ||
613 | V4L2_STD_SECAM_LC)) && | ||
614 | !(params->std & ~(V4L2_STD_SECAM_L | | ||
615 | V4L2_STD_SECAM_LC)); | ||
616 | |||
617 | tda9887_cfg.tuner = TUNER_TDA9887; | ||
618 | tda9887_cfg.priv = &tda_config; | ||
619 | |||
620 | if (params->std == V4L2_STD_SECAM_LC) { | ||
621 | if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc) | ||
622 | tda_config |= TDA9887_PORT1_ACTIVE; | ||
623 | if (t_params->port2_active ^ t_params->port2_invert_for_secam_lc) | ||
624 | tda_config |= TDA9887_PORT2_ACTIVE; | ||
625 | } else { | ||
626 | if (t_params->port1_active) | ||
627 | tda_config |= TDA9887_PORT1_ACTIVE; | ||
628 | if (t_params->port2_active) | ||
629 | tda_config |= TDA9887_PORT2_ACTIVE; | ||
630 | } | ||
631 | if (t_params->intercarrier_mode) | ||
632 | tda_config |= TDA9887_INTERCARRIER; | ||
633 | if (is_secam_l) { | ||
634 | if (i == 0 && t_params->default_top_secam_low) | ||
635 | tda_config |= TDA9887_TOP(t_params->default_top_secam_low); | ||
636 | else if (i == 1 && t_params->default_top_secam_mid) | ||
637 | tda_config |= TDA9887_TOP(t_params->default_top_secam_mid); | ||
638 | else if (t_params->default_top_secam_high) | ||
639 | tda_config |= TDA9887_TOP(t_params->default_top_secam_high); | ||
640 | } else { | ||
641 | if (i == 0 && t_params->default_top_low) | ||
642 | tda_config |= TDA9887_TOP(t_params->default_top_low); | ||
643 | else if (i == 1 && t_params->default_top_mid) | ||
644 | tda_config |= TDA9887_TOP(t_params->default_top_mid); | ||
645 | else if (t_params->default_top_high) | ||
646 | tda_config |= TDA9887_TOP(t_params->default_top_high); | ||
647 | } | ||
648 | if (t_params->default_pll_gating_18) | ||
649 | tda_config |= TDA9887_GATING_18; | ||
650 | i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG, | ||
651 | &tda9887_cfg); | ||
652 | } | ||
653 | tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n", | ||
654 | buffer[0], buffer[1], buffer[2], buffer[3]); | ||
655 | |||
656 | rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4); | ||
657 | if (4 != rc) | ||
658 | tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc); | ||
659 | |||
660 | simple_post_tune(fe, &buffer[0], div, config, cb); | ||
661 | |||
662 | return 0; | ||
663 | } | ||
664 | |||
665 | static int simple_set_radio_freq(struct dvb_frontend *fe, | ||
666 | struct analog_parameters *params) | ||
667 | { | ||
668 | struct tunertype *tun; | ||
669 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
670 | u8 buffer[4]; | ||
671 | u16 div; | ||
672 | int rc, j; | ||
673 | struct tuner_params *t_params; | ||
674 | unsigned int freq = params->frequency; | ||
675 | |||
676 | tun = priv->tun; | ||
677 | |||
678 | for (j = tun->count-1; j > 0; j--) | ||
679 | if (tun->params[j].type == TUNER_PARAM_TYPE_RADIO) | ||
680 | break; | ||
681 | /* default t_params (j=0) will be used if desired type wasn't found */ | ||
682 | t_params = &tun->params[j]; | ||
683 | |||
684 | /* Select Radio 1st IF used */ | ||
685 | switch (t_params->radio_if) { | ||
686 | case 0: /* 10.7 MHz */ | ||
687 | freq += (unsigned int)(10.7*16000); | ||
688 | break; | ||
689 | case 1: /* 33.3 MHz */ | ||
690 | freq += (unsigned int)(33.3*16000); | ||
691 | break; | ||
692 | case 2: /* 41.3 MHz */ | ||
693 | freq += (unsigned int)(41.3*16000); | ||
694 | break; | ||
695 | default: | ||
696 | tuner_warn("Unsupported radio_if value %d\n", | ||
697 | t_params->radio_if); | ||
698 | return 0; | ||
699 | } | ||
700 | |||
701 | buffer[2] = (t_params->ranges[0].config & ~TUNER_RATIO_MASK) | | ||
702 | TUNER_RATIO_SELECT_50; /* 50 kHz step */ | ||
703 | |||
704 | /* Bandswitch byte */ | ||
705 | simple_radio_bandswitch(fe, &buffer[0]); | ||
706 | |||
707 | /* Convert from 1/16 kHz V4L steps to 1/20 MHz (=50 kHz) PLL steps | ||
708 | freq * (1 Mhz / 16000 V4L steps) * (20 PLL steps / 1 MHz) = | ||
709 | freq * (1/800) */ | ||
710 | div = (freq + 400) / 800; | ||
711 | |||
712 | if (t_params->cb_first_if_lower_freq && div < priv->last_div) { | ||
713 | buffer[0] = buffer[2]; | ||
714 | buffer[1] = buffer[3]; | ||
715 | buffer[2] = (div>>8) & 0x7f; | ||
716 | buffer[3] = div & 0xff; | ||
717 | } else { | ||
718 | buffer[0] = (div>>8) & 0x7f; | ||
719 | buffer[1] = div & 0xff; | ||
720 | } | ||
721 | |||
722 | tuner_dbg("radio 0x%02x 0x%02x 0x%02x 0x%02x\n", | ||
723 | buffer[0], buffer[1], buffer[2], buffer[3]); | ||
724 | priv->last_div = div; | ||
725 | |||
726 | if (t_params->has_tda9887) { | ||
727 | int config = 0; | ||
728 | struct v4l2_priv_tun_config tda9887_cfg; | ||
729 | |||
730 | tda9887_cfg.tuner = TUNER_TDA9887; | ||
731 | tda9887_cfg.priv = &config; | ||
732 | |||
733 | if (t_params->port1_active && | ||
734 | !t_params->port1_fm_high_sensitivity) | ||
735 | config |= TDA9887_PORT1_ACTIVE; | ||
736 | if (t_params->port2_active && | ||
737 | !t_params->port2_fm_high_sensitivity) | ||
738 | config |= TDA9887_PORT2_ACTIVE; | ||
739 | if (t_params->intercarrier_mode) | ||
740 | config |= TDA9887_INTERCARRIER; | ||
741 | /* if (t_params->port1_set_for_fm_mono) | ||
742 | config &= ~TDA9887_PORT1_ACTIVE;*/ | ||
743 | if (t_params->fm_gain_normal) | ||
744 | config |= TDA9887_GAIN_NORMAL; | ||
745 | if (t_params->radio_if == 2) | ||
746 | config |= TDA9887_RIF_41_3; | ||
747 | i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG, | ||
748 | &tda9887_cfg); | ||
749 | } | ||
750 | rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4); | ||
751 | if (4 != rc) | ||
752 | tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc); | ||
753 | |||
754 | /* Write AUX byte */ | ||
755 | switch (priv->type) { | ||
756 | case TUNER_PHILIPS_FM1216ME_MK3: | ||
757 | buffer[2] = 0x98; | ||
758 | buffer[3] = 0x20; /* set TOP AGC */ | ||
759 | rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4); | ||
760 | if (4 != rc) | ||
761 | tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc); | ||
762 | break; | ||
763 | } | ||
764 | |||
765 | return 0; | ||
766 | } | ||
767 | |||
768 | static int simple_set_params(struct dvb_frontend *fe, | ||
769 | struct analog_parameters *params) | ||
770 | { | ||
771 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
772 | int ret = -EINVAL; | ||
773 | |||
774 | if (priv->i2c_props.adap == NULL) | ||
775 | return -EINVAL; | ||
776 | |||
777 | switch (params->mode) { | ||
778 | case V4L2_TUNER_RADIO: | ||
779 | ret = simple_set_radio_freq(fe, params); | ||
780 | priv->frequency = params->frequency * 125 / 2; | ||
781 | break; | ||
782 | case V4L2_TUNER_ANALOG_TV: | ||
783 | case V4L2_TUNER_DIGITAL_TV: | ||
784 | ret = simple_set_tv_freq(fe, params); | ||
785 | priv->frequency = params->frequency * 62500; | ||
786 | break; | ||
787 | } | ||
788 | priv->bandwidth = 0; | ||
789 | |||
790 | return ret; | ||
791 | } | ||
792 | |||
793 | static void simple_set_dvb(struct dvb_frontend *fe, u8 *buf, | ||
794 | const u32 delsys, | ||
795 | const u32 frequency, | ||
796 | const u32 bandwidth) | ||
797 | { | ||
798 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
799 | |||
800 | switch (priv->type) { | ||
801 | case TUNER_PHILIPS_FMD1216ME_MK3: | ||
802 | case TUNER_PHILIPS_FMD1216MEX_MK3: | ||
803 | if (bandwidth == 8000000 && | ||
804 | frequency >= 158870000) | ||
805 | buf[3] |= 0x08; | ||
806 | break; | ||
807 | case TUNER_PHILIPS_TD1316: | ||
808 | /* determine band */ | ||
809 | buf[3] |= (frequency < 161000000) ? 1 : | ||
810 | (frequency < 444000000) ? 2 : 4; | ||
811 | |||
812 | /* setup PLL filter */ | ||
813 | if (bandwidth == 8000000) | ||
814 | buf[3] |= 1 << 3; | ||
815 | break; | ||
816 | case TUNER_PHILIPS_TUV1236D: | ||
817 | case TUNER_PHILIPS_FCV1236D: | ||
818 | { | ||
819 | unsigned int new_rf; | ||
820 | |||
821 | if (dtv_input[priv->nr]) | ||
822 | new_rf = dtv_input[priv->nr]; | ||
823 | else | ||
824 | switch (delsys) { | ||
825 | case SYS_DVBC_ANNEX_B: | ||
826 | new_rf = 1; | ||
827 | break; | ||
828 | case SYS_ATSC: | ||
829 | default: | ||
830 | new_rf = 0; | ||
831 | break; | ||
832 | } | ||
833 | simple_set_rf_input(fe, &buf[2], &buf[3], new_rf); | ||
834 | break; | ||
835 | } | ||
836 | default: | ||
837 | break; | ||
838 | } | ||
839 | } | ||
840 | |||
841 | static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf, | ||
842 | const u32 delsys, | ||
843 | const u32 freq, | ||
844 | const u32 bw) | ||
845 | { | ||
846 | /* This function returns the tuned frequency on success, 0 on error */ | ||
847 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
848 | struct tunertype *tun = priv->tun; | ||
849 | static struct tuner_params *t_params; | ||
850 | u8 config, cb; | ||
851 | u32 div; | ||
852 | int ret; | ||
853 | u32 frequency = freq / 62500; | ||
854 | |||
855 | if (!tun->stepsize) { | ||
856 | /* tuner-core was loaded before the digital tuner was | ||
857 | * configured and somehow picked the wrong tuner type */ | ||
858 | tuner_err("attempt to treat tuner %d (%s) as digital tuner " | ||
859 | "without stepsize defined.\n", | ||
860 | priv->type, priv->tun->name); | ||
861 | return 0; /* failure */ | ||
862 | } | ||
863 | |||
864 | t_params = simple_tuner_params(fe, TUNER_PARAM_TYPE_DIGITAL); | ||
865 | ret = simple_config_lookup(fe, t_params, &frequency, &config, &cb); | ||
866 | if (ret < 0) | ||
867 | return 0; /* failure */ | ||
868 | |||
869 | div = ((frequency + t_params->iffreq) * 62500 + offset + | ||
870 | tun->stepsize/2) / tun->stepsize; | ||
871 | |||
872 | buf[0] = div >> 8; | ||
873 | buf[1] = div & 0xff; | ||
874 | buf[2] = config; | ||
875 | buf[3] = cb; | ||
876 | |||
877 | simple_set_dvb(fe, buf, delsys, freq, bw); | ||
878 | |||
879 | tuner_dbg("%s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n", | ||
880 | tun->name, div, buf[0], buf[1], buf[2], buf[3]); | ||
881 | |||
882 | /* calculate the frequency we set it to */ | ||
883 | return (div * tun->stepsize) - t_params->iffreq; | ||
884 | } | ||
885 | |||
886 | static int simple_dvb_calc_regs(struct dvb_frontend *fe, | ||
887 | u8 *buf, int buf_len) | ||
888 | { | ||
889 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
890 | u32 delsys = c->delivery_system; | ||
891 | u32 bw = c->bandwidth_hz; | ||
892 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
893 | u32 frequency; | ||
894 | |||
895 | if (buf_len < 5) | ||
896 | return -EINVAL; | ||
897 | |||
898 | frequency = simple_dvb_configure(fe, buf+1, delsys, c->frequency, bw); | ||
899 | if (frequency == 0) | ||
900 | return -EINVAL; | ||
901 | |||
902 | buf[0] = priv->i2c_props.addr; | ||
903 | |||
904 | priv->frequency = frequency; | ||
905 | priv->bandwidth = c->bandwidth_hz; | ||
906 | |||
907 | return 5; | ||
908 | } | ||
909 | |||
910 | static int simple_dvb_set_params(struct dvb_frontend *fe) | ||
911 | { | ||
912 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
913 | u32 delsys = c->delivery_system; | ||
914 | u32 bw = c->bandwidth_hz; | ||
915 | u32 freq = c->frequency; | ||
916 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
917 | u32 frequency; | ||
918 | u32 prev_freq, prev_bw; | ||
919 | int ret; | ||
920 | u8 buf[5]; | ||
921 | |||
922 | if (priv->i2c_props.adap == NULL) | ||
923 | return -EINVAL; | ||
924 | |||
925 | prev_freq = priv->frequency; | ||
926 | prev_bw = priv->bandwidth; | ||
927 | |||
928 | frequency = simple_dvb_configure(fe, buf+1, delsys, freq, bw); | ||
929 | if (frequency == 0) | ||
930 | return -EINVAL; | ||
931 | |||
932 | buf[0] = priv->i2c_props.addr; | ||
933 | |||
934 | priv->frequency = frequency; | ||
935 | priv->bandwidth = bw; | ||
936 | |||
937 | /* put analog demod in standby when tuning digital */ | ||
938 | if (fe->ops.analog_ops.standby) | ||
939 | fe->ops.analog_ops.standby(fe); | ||
940 | |||
941 | if (fe->ops.i2c_gate_ctrl) | ||
942 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
943 | |||
944 | /* buf[0] contains the i2c address, but * | ||
945 | * we already have it in i2c_props.addr */ | ||
946 | ret = tuner_i2c_xfer_send(&priv->i2c_props, buf+1, 4); | ||
947 | if (ret != 4) | ||
948 | goto fail; | ||
949 | |||
950 | return 0; | ||
951 | fail: | ||
952 | /* calc_regs sets frequency and bandwidth. if we failed, unset them */ | ||
953 | priv->frequency = prev_freq; | ||
954 | priv->bandwidth = prev_bw; | ||
955 | |||
956 | return ret; | ||
957 | } | ||
958 | |||
959 | static int simple_init(struct dvb_frontend *fe) | ||
960 | { | ||
961 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
962 | |||
963 | if (priv->i2c_props.adap == NULL) | ||
964 | return -EINVAL; | ||
965 | |||
966 | if (priv->tun->initdata) { | ||
967 | int ret; | ||
968 | |||
969 | if (fe->ops.i2c_gate_ctrl) | ||
970 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
971 | |||
972 | ret = tuner_i2c_xfer_send(&priv->i2c_props, | ||
973 | priv->tun->initdata + 1, | ||
974 | priv->tun->initdata[0]); | ||
975 | if (ret != priv->tun->initdata[0]) | ||
976 | return ret; | ||
977 | } | ||
978 | |||
979 | return 0; | ||
980 | } | ||
981 | |||
982 | static int simple_sleep(struct dvb_frontend *fe) | ||
983 | { | ||
984 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
985 | |||
986 | if (priv->i2c_props.adap == NULL) | ||
987 | return -EINVAL; | ||
988 | |||
989 | if (priv->tun->sleepdata) { | ||
990 | int ret; | ||
991 | |||
992 | if (fe->ops.i2c_gate_ctrl) | ||
993 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
994 | |||
995 | ret = tuner_i2c_xfer_send(&priv->i2c_props, | ||
996 | priv->tun->sleepdata + 1, | ||
997 | priv->tun->sleepdata[0]); | ||
998 | if (ret != priv->tun->sleepdata[0]) | ||
999 | return ret; | ||
1000 | } | ||
1001 | |||
1002 | return 0; | ||
1003 | } | ||
1004 | |||
1005 | static int simple_release(struct dvb_frontend *fe) | ||
1006 | { | ||
1007 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
1008 | |||
1009 | mutex_lock(&tuner_simple_list_mutex); | ||
1010 | |||
1011 | if (priv) | ||
1012 | hybrid_tuner_release_state(priv); | ||
1013 | |||
1014 | mutex_unlock(&tuner_simple_list_mutex); | ||
1015 | |||
1016 | fe->tuner_priv = NULL; | ||
1017 | |||
1018 | return 0; | ||
1019 | } | ||
1020 | |||
1021 | static int simple_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
1022 | { | ||
1023 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
1024 | *frequency = priv->frequency; | ||
1025 | return 0; | ||
1026 | } | ||
1027 | |||
1028 | static int simple_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) | ||
1029 | { | ||
1030 | struct tuner_simple_priv *priv = fe->tuner_priv; | ||
1031 | *bandwidth = priv->bandwidth; | ||
1032 | return 0; | ||
1033 | } | ||
1034 | |||
1035 | static struct dvb_tuner_ops simple_tuner_ops = { | ||
1036 | .init = simple_init, | ||
1037 | .sleep = simple_sleep, | ||
1038 | .set_analog_params = simple_set_params, | ||
1039 | .set_params = simple_dvb_set_params, | ||
1040 | .calc_regs = simple_dvb_calc_regs, | ||
1041 | .release = simple_release, | ||
1042 | .get_frequency = simple_get_frequency, | ||
1043 | .get_bandwidth = simple_get_bandwidth, | ||
1044 | .get_status = simple_get_status, | ||
1045 | .get_rf_strength = simple_get_rf_strength, | ||
1046 | }; | ||
1047 | |||
1048 | struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, | ||
1049 | struct i2c_adapter *i2c_adap, | ||
1050 | u8 i2c_addr, | ||
1051 | unsigned int type) | ||
1052 | { | ||
1053 | struct tuner_simple_priv *priv = NULL; | ||
1054 | int instance; | ||
1055 | |||
1056 | if (type >= tuner_count) { | ||
1057 | printk(KERN_WARNING "%s: invalid tuner type: %d (max: %d)\n", | ||
1058 | __func__, type, tuner_count-1); | ||
1059 | return NULL; | ||
1060 | } | ||
1061 | |||
1062 | /* If i2c_adap is set, check that the tuner is at the correct address. | ||
1063 | * Otherwise, if i2c_adap is NULL, the tuner will be programmed directly | ||
1064 | * by the digital demod via calc_regs. | ||
1065 | */ | ||
1066 | if (i2c_adap != NULL) { | ||
1067 | u8 b[1]; | ||
1068 | struct i2c_msg msg = { | ||
1069 | .addr = i2c_addr, .flags = I2C_M_RD, | ||
1070 | .buf = b, .len = 1, | ||
1071 | }; | ||
1072 | |||
1073 | if (fe->ops.i2c_gate_ctrl) | ||
1074 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
1075 | |||
1076 | if (1 != i2c_transfer(i2c_adap, &msg, 1)) | ||
1077 | printk(KERN_WARNING "tuner-simple %d-%04x: " | ||
1078 | "unable to probe %s, proceeding anyway.", | ||
1079 | i2c_adapter_id(i2c_adap), i2c_addr, | ||
1080 | tuners[type].name); | ||
1081 | |||
1082 | if (fe->ops.i2c_gate_ctrl) | ||
1083 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
1084 | } | ||
1085 | |||
1086 | mutex_lock(&tuner_simple_list_mutex); | ||
1087 | |||
1088 | instance = hybrid_tuner_request_state(struct tuner_simple_priv, priv, | ||
1089 | hybrid_tuner_instance_list, | ||
1090 | i2c_adap, i2c_addr, | ||
1091 | "tuner-simple"); | ||
1092 | switch (instance) { | ||
1093 | case 0: | ||
1094 | mutex_unlock(&tuner_simple_list_mutex); | ||
1095 | return NULL; | ||
1096 | case 1: | ||
1097 | fe->tuner_priv = priv; | ||
1098 | |||
1099 | priv->type = type; | ||
1100 | priv->tun = &tuners[type]; | ||
1101 | priv->nr = simple_devcount++; | ||
1102 | break; | ||
1103 | default: | ||
1104 | fe->tuner_priv = priv; | ||
1105 | break; | ||
1106 | } | ||
1107 | |||
1108 | mutex_unlock(&tuner_simple_list_mutex); | ||
1109 | |||
1110 | memcpy(&fe->ops.tuner_ops, &simple_tuner_ops, | ||
1111 | sizeof(struct dvb_tuner_ops)); | ||
1112 | |||
1113 | if (type != priv->type) | ||
1114 | tuner_warn("couldn't set type to %d. Using %d (%s) instead\n", | ||
1115 | type, priv->type, priv->tun->name); | ||
1116 | else | ||
1117 | tuner_info("type set to %d (%s)\n", | ||
1118 | priv->type, priv->tun->name); | ||
1119 | |||
1120 | if ((debug) || ((atv_input[priv->nr] > 0) || | ||
1121 | (dtv_input[priv->nr] > 0))) { | ||
1122 | if (0 == atv_input[priv->nr]) | ||
1123 | tuner_info("tuner %d atv rf input will be " | ||
1124 | "autoselected\n", priv->nr); | ||
1125 | else | ||
1126 | tuner_info("tuner %d atv rf input will be " | ||
1127 | "set to input %d (insmod option)\n", | ||
1128 | priv->nr, atv_input[priv->nr]); | ||
1129 | if (0 == dtv_input[priv->nr]) | ||
1130 | tuner_info("tuner %d dtv rf input will be " | ||
1131 | "autoselected\n", priv->nr); | ||
1132 | else | ||
1133 | tuner_info("tuner %d dtv rf input will be " | ||
1134 | "set to input %d (insmod option)\n", | ||
1135 | priv->nr, dtv_input[priv->nr]); | ||
1136 | } | ||
1137 | |||
1138 | strlcpy(fe->ops.tuner_ops.info.name, priv->tun->name, | ||
1139 | sizeof(fe->ops.tuner_ops.info.name)); | ||
1140 | |||
1141 | return fe; | ||
1142 | } | ||
1143 | EXPORT_SYMBOL_GPL(simple_tuner_attach); | ||
1144 | |||
1145 | MODULE_DESCRIPTION("Simple 4-control-bytes style tuner driver"); | ||
1146 | MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); | ||
1147 | MODULE_LICENSE("GPL"); | ||
1148 | |||
1149 | /* | ||
1150 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
1151 | * --------------------------------------------------------------------------- | ||
1152 | * Local variables: | ||
1153 | * c-basic-offset: 8 | ||
1154 | * End: | ||
1155 | */ | ||
diff --git a/drivers/media/tuners/tuner-simple.h b/drivers/media/tuners/tuner-simple.h new file mode 100644 index 000000000000..381fa5d35a9b --- /dev/null +++ b/drivers/media/tuners/tuner-simple.h | |||
@@ -0,0 +1,39 @@ | |||
1 | /* | ||
2 | This program is free software; you can redistribute it and/or modify | ||
3 | it under the terms of the GNU General Public License as published by | ||
4 | the Free Software Foundation; either version 2 of the License, or | ||
5 | (at your option) any later version. | ||
6 | |||
7 | This program is distributed in the hope that it will be useful, | ||
8 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | GNU General Public License for more details. | ||
11 | |||
12 | You should have received a copy of the GNU General Public License | ||
13 | along with this program; if not, write to the Free Software | ||
14 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
15 | */ | ||
16 | |||
17 | #ifndef __TUNER_SIMPLE_H__ | ||
18 | #define __TUNER_SIMPLE_H__ | ||
19 | |||
20 | #include <linux/i2c.h> | ||
21 | #include "dvb_frontend.h" | ||
22 | |||
23 | #if defined(CONFIG_MEDIA_TUNER_SIMPLE) || (defined(CONFIG_MEDIA_TUNER_SIMPLE_MODULE) && defined(MODULE)) | ||
24 | extern struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, | ||
25 | struct i2c_adapter *i2c_adap, | ||
26 | u8 i2c_addr, | ||
27 | unsigned int type); | ||
28 | #else | ||
29 | static inline struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, | ||
30 | struct i2c_adapter *i2c_adap, | ||
31 | u8 i2c_addr, | ||
32 | unsigned int type) | ||
33 | { | ||
34 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
35 | return NULL; | ||
36 | } | ||
37 | #endif | ||
38 | |||
39 | #endif /* __TUNER_SIMPLE_H__ */ | ||
diff --git a/drivers/media/tuners/tuner-types.c b/drivers/media/tuners/tuner-types.c new file mode 100644 index 000000000000..2da4440c16ee --- /dev/null +++ b/drivers/media/tuners/tuner-types.c | |||
@@ -0,0 +1,1883 @@ | |||
1 | /* | ||
2 | * | ||
3 | * i2c tv tuner chip device type database. | ||
4 | * | ||
5 | */ | ||
6 | |||
7 | #include <linux/i2c.h> | ||
8 | #include <linux/module.h> | ||
9 | #include <media/tuner.h> | ||
10 | #include <media/tuner-types.h> | ||
11 | |||
12 | /* ---------------------------------------------------------------------- */ | ||
13 | |||
14 | /* | ||
15 | * The floats in the tuner struct are computed at compile time | ||
16 | * by gcc and cast back to integers. Thus we don't violate the | ||
17 | * "no float in kernel" rule. | ||
18 | * | ||
19 | * A tuner_range may be referenced by multiple tuner_params structs. | ||
20 | * There are many duplicates in here. Reusing tuner_range structs, | ||
21 | * rather than defining new ones for each tuner, will cut down on | ||
22 | * memory usage, and is preferred when possible. | ||
23 | * | ||
24 | * Each tuner_params array may contain one or more elements, one | ||
25 | * for each video standard. | ||
26 | * | ||
27 | * FIXME: tuner_params struct contains an element, tda988x. We must | ||
28 | * set this for all tuners that contain a tda988x chip, and then we | ||
29 | * can remove this setting from the various card structs. | ||
30 | * | ||
31 | * FIXME: Right now, all tuners are using the first tuner_params[] | ||
32 | * array element for analog mode. In the future, we will be merging | ||
33 | * similar tuner definitions together, such that each tuner definition | ||
34 | * will have a tuner_params struct for each available video standard. | ||
35 | * At that point, the tuner_params[] array element will be chosen | ||
36 | * based on the video standard in use. | ||
37 | */ | ||
38 | |||
39 | /* The following was taken from dvb-pll.c: */ | ||
40 | |||
41 | /* Set AGC TOP value to 103 dBuV: | ||
42 | * 0x80 = Control Byte | ||
43 | * 0x40 = 250 uA charge pump (irrelevant) | ||
44 | * 0x18 = Aux Byte to follow | ||
45 | * 0x06 = 64.5 kHz divider (irrelevant) | ||
46 | * 0x01 = Disable Vt (aka sleep) | ||
47 | * | ||
48 | * 0x00 = AGC Time constant 2s Iagc = 300 nA (vs 0x80 = 9 nA) | ||
49 | * 0x50 = AGC Take over point = 103 dBuV | ||
50 | */ | ||
51 | static u8 tua603x_agc103[] = { 2, 0x80|0x40|0x18|0x06|0x01, 0x00|0x50 }; | ||
52 | |||
53 | /* 0x04 = 166.67 kHz divider | ||
54 | * | ||
55 | * 0x80 = AGC Time constant 50ms Iagc = 9 uA | ||
56 | * 0x20 = AGC Take over point = 112 dBuV | ||
57 | */ | ||
58 | static u8 tua603x_agc112[] = { 2, 0x80|0x40|0x18|0x04|0x01, 0x80|0x20 }; | ||
59 | |||
60 | /* 0-9 */ | ||
61 | /* ------------ TUNER_TEMIC_PAL - TEMIC PAL ------------ */ | ||
62 | |||
63 | static struct tuner_range tuner_temic_pal_ranges[] = { | ||
64 | { 16 * 140.25 /*MHz*/, 0x8e, 0x02, }, | ||
65 | { 16 * 463.25 /*MHz*/, 0x8e, 0x04, }, | ||
66 | { 16 * 999.99 , 0x8e, 0x01, }, | ||
67 | }; | ||
68 | |||
69 | static struct tuner_params tuner_temic_pal_params[] = { | ||
70 | { | ||
71 | .type = TUNER_PARAM_TYPE_PAL, | ||
72 | .ranges = tuner_temic_pal_ranges, | ||
73 | .count = ARRAY_SIZE(tuner_temic_pal_ranges), | ||
74 | }, | ||
75 | }; | ||
76 | |||
77 | /* ------------ TUNER_PHILIPS_PAL_I - Philips PAL_I ------------ */ | ||
78 | |||
79 | static struct tuner_range tuner_philips_pal_i_ranges[] = { | ||
80 | { 16 * 140.25 /*MHz*/, 0x8e, 0xa0, }, | ||
81 | { 16 * 463.25 /*MHz*/, 0x8e, 0x90, }, | ||
82 | { 16 * 999.99 , 0x8e, 0x30, }, | ||
83 | }; | ||
84 | |||
85 | static struct tuner_params tuner_philips_pal_i_params[] = { | ||
86 | { | ||
87 | .type = TUNER_PARAM_TYPE_PAL, | ||
88 | .ranges = tuner_philips_pal_i_ranges, | ||
89 | .count = ARRAY_SIZE(tuner_philips_pal_i_ranges), | ||
90 | }, | ||
91 | }; | ||
92 | |||
93 | /* ------------ TUNER_PHILIPS_NTSC - Philips NTSC ------------ */ | ||
94 | |||
95 | static struct tuner_range tuner_philips_ntsc_ranges[] = { | ||
96 | { 16 * 157.25 /*MHz*/, 0x8e, 0xa0, }, | ||
97 | { 16 * 451.25 /*MHz*/, 0x8e, 0x90, }, | ||
98 | { 16 * 999.99 , 0x8e, 0x30, }, | ||
99 | }; | ||
100 | |||
101 | static struct tuner_params tuner_philips_ntsc_params[] = { | ||
102 | { | ||
103 | .type = TUNER_PARAM_TYPE_NTSC, | ||
104 | .ranges = tuner_philips_ntsc_ranges, | ||
105 | .count = ARRAY_SIZE(tuner_philips_ntsc_ranges), | ||
106 | .cb_first_if_lower_freq = 1, | ||
107 | }, | ||
108 | }; | ||
109 | |||
110 | /* ------------ TUNER_PHILIPS_SECAM - Philips SECAM ------------ */ | ||
111 | |||
112 | static struct tuner_range tuner_philips_secam_ranges[] = { | ||
113 | { 16 * 168.25 /*MHz*/, 0x8e, 0xa7, }, | ||
114 | { 16 * 447.25 /*MHz*/, 0x8e, 0x97, }, | ||
115 | { 16 * 999.99 , 0x8e, 0x37, }, | ||
116 | }; | ||
117 | |||
118 | static struct tuner_params tuner_philips_secam_params[] = { | ||
119 | { | ||
120 | .type = TUNER_PARAM_TYPE_SECAM, | ||
121 | .ranges = tuner_philips_secam_ranges, | ||
122 | .count = ARRAY_SIZE(tuner_philips_secam_ranges), | ||
123 | .cb_first_if_lower_freq = 1, | ||
124 | }, | ||
125 | }; | ||
126 | |||
127 | /* ------------ TUNER_PHILIPS_PAL - Philips PAL ------------ */ | ||
128 | |||
129 | static struct tuner_range tuner_philips_pal_ranges[] = { | ||
130 | { 16 * 168.25 /*MHz*/, 0x8e, 0xa0, }, | ||
131 | { 16 * 447.25 /*MHz*/, 0x8e, 0x90, }, | ||
132 | { 16 * 999.99 , 0x8e, 0x30, }, | ||
133 | }; | ||
134 | |||
135 | static struct tuner_params tuner_philips_pal_params[] = { | ||
136 | { | ||
137 | .type = TUNER_PARAM_TYPE_PAL, | ||
138 | .ranges = tuner_philips_pal_ranges, | ||
139 | .count = ARRAY_SIZE(tuner_philips_pal_ranges), | ||
140 | .cb_first_if_lower_freq = 1, | ||
141 | }, | ||
142 | }; | ||
143 | |||
144 | /* ------------ TUNER_TEMIC_NTSC - TEMIC NTSC ------------ */ | ||
145 | |||
146 | static struct tuner_range tuner_temic_ntsc_ranges[] = { | ||
147 | { 16 * 157.25 /*MHz*/, 0x8e, 0x02, }, | ||
148 | { 16 * 463.25 /*MHz*/, 0x8e, 0x04, }, | ||
149 | { 16 * 999.99 , 0x8e, 0x01, }, | ||
150 | }; | ||
151 | |||
152 | static struct tuner_params tuner_temic_ntsc_params[] = { | ||
153 | { | ||
154 | .type = TUNER_PARAM_TYPE_NTSC, | ||
155 | .ranges = tuner_temic_ntsc_ranges, | ||
156 | .count = ARRAY_SIZE(tuner_temic_ntsc_ranges), | ||
157 | }, | ||
158 | }; | ||
159 | |||
160 | /* ------------ TUNER_TEMIC_PAL_I - TEMIC PAL_I ------------ */ | ||
161 | |||
162 | static struct tuner_range tuner_temic_pal_i_ranges[] = { | ||
163 | { 16 * 170.00 /*MHz*/, 0x8e, 0x02, }, | ||
164 | { 16 * 450.00 /*MHz*/, 0x8e, 0x04, }, | ||
165 | { 16 * 999.99 , 0x8e, 0x01, }, | ||
166 | }; | ||
167 | |||
168 | static struct tuner_params tuner_temic_pal_i_params[] = { | ||
169 | { | ||
170 | .type = TUNER_PARAM_TYPE_PAL, | ||
171 | .ranges = tuner_temic_pal_i_ranges, | ||
172 | .count = ARRAY_SIZE(tuner_temic_pal_i_ranges), | ||
173 | }, | ||
174 | }; | ||
175 | |||
176 | /* ------------ TUNER_TEMIC_4036FY5_NTSC - TEMIC NTSC ------------ */ | ||
177 | |||
178 | static struct tuner_range tuner_temic_4036fy5_ntsc_ranges[] = { | ||
179 | { 16 * 157.25 /*MHz*/, 0x8e, 0xa0, }, | ||
180 | { 16 * 463.25 /*MHz*/, 0x8e, 0x90, }, | ||
181 | { 16 * 999.99 , 0x8e, 0x30, }, | ||
182 | }; | ||
183 | |||
184 | static struct tuner_params tuner_temic_4036fy5_ntsc_params[] = { | ||
185 | { | ||
186 | .type = TUNER_PARAM_TYPE_NTSC, | ||
187 | .ranges = tuner_temic_4036fy5_ntsc_ranges, | ||
188 | .count = ARRAY_SIZE(tuner_temic_4036fy5_ntsc_ranges), | ||
189 | }, | ||
190 | }; | ||
191 | |||
192 | /* ------------ TUNER_ALPS_TSBH1_NTSC - TEMIC NTSC ------------ */ | ||
193 | |||
194 | static struct tuner_range tuner_alps_tsb_1_ranges[] = { | ||
195 | { 16 * 137.25 /*MHz*/, 0x8e, 0x01, }, | ||
196 | { 16 * 385.25 /*MHz*/, 0x8e, 0x02, }, | ||
197 | { 16 * 999.99 , 0x8e, 0x08, }, | ||
198 | }; | ||
199 | |||
200 | static struct tuner_params tuner_alps_tsbh1_ntsc_params[] = { | ||
201 | { | ||
202 | .type = TUNER_PARAM_TYPE_NTSC, | ||
203 | .ranges = tuner_alps_tsb_1_ranges, | ||
204 | .count = ARRAY_SIZE(tuner_alps_tsb_1_ranges), | ||
205 | }, | ||
206 | }; | ||
207 | |||
208 | /* 10-19 */ | ||
209 | /* ------------ TUNER_ALPS_TSBE1_PAL - TEMIC PAL ------------ */ | ||
210 | |||
211 | static struct tuner_params tuner_alps_tsb_1_params[] = { | ||
212 | { | ||
213 | .type = TUNER_PARAM_TYPE_PAL, | ||
214 | .ranges = tuner_alps_tsb_1_ranges, | ||
215 | .count = ARRAY_SIZE(tuner_alps_tsb_1_ranges), | ||
216 | }, | ||
217 | }; | ||
218 | |||
219 | /* ------------ TUNER_ALPS_TSBB5_PAL_I - Alps PAL_I ------------ */ | ||
220 | |||
221 | static struct tuner_range tuner_alps_tsb_5_pal_ranges[] = { | ||
222 | { 16 * 133.25 /*MHz*/, 0x8e, 0x01, }, | ||
223 | { 16 * 351.25 /*MHz*/, 0x8e, 0x02, }, | ||
224 | { 16 * 999.99 , 0x8e, 0x08, }, | ||
225 | }; | ||
226 | |||
227 | static struct tuner_params tuner_alps_tsbb5_params[] = { | ||
228 | { | ||
229 | .type = TUNER_PARAM_TYPE_PAL, | ||
230 | .ranges = tuner_alps_tsb_5_pal_ranges, | ||
231 | .count = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges), | ||
232 | }, | ||
233 | }; | ||
234 | |||
235 | /* ------------ TUNER_ALPS_TSBE5_PAL - Alps PAL ------------ */ | ||
236 | |||
237 | static struct tuner_params tuner_alps_tsbe5_params[] = { | ||
238 | { | ||
239 | .type = TUNER_PARAM_TYPE_PAL, | ||
240 | .ranges = tuner_alps_tsb_5_pal_ranges, | ||
241 | .count = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges), | ||
242 | }, | ||
243 | }; | ||
244 | |||
245 | /* ------------ TUNER_ALPS_TSBC5_PAL - Alps PAL ------------ */ | ||
246 | |||
247 | static struct tuner_params tuner_alps_tsbc5_params[] = { | ||
248 | { | ||
249 | .type = TUNER_PARAM_TYPE_PAL, | ||
250 | .ranges = tuner_alps_tsb_5_pal_ranges, | ||
251 | .count = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges), | ||
252 | }, | ||
253 | }; | ||
254 | |||
255 | /* ------------ TUNER_TEMIC_4006FH5_PAL - TEMIC PAL ------------ */ | ||
256 | |||
257 | static struct tuner_range tuner_lg_pal_ranges[] = { | ||
258 | { 16 * 170.00 /*MHz*/, 0x8e, 0xa0, }, | ||
259 | { 16 * 450.00 /*MHz*/, 0x8e, 0x90, }, | ||
260 | { 16 * 999.99 , 0x8e, 0x30, }, | ||
261 | }; | ||
262 | |||
263 | static struct tuner_params tuner_temic_4006fh5_params[] = { | ||
264 | { | ||
265 | .type = TUNER_PARAM_TYPE_PAL, | ||
266 | .ranges = tuner_lg_pal_ranges, | ||
267 | .count = ARRAY_SIZE(tuner_lg_pal_ranges), | ||
268 | }, | ||
269 | }; | ||
270 | |||
271 | /* ------------ TUNER_ALPS_TSHC6_NTSC - Alps NTSC ------------ */ | ||
272 | |||
273 | static struct tuner_range tuner_alps_tshc6_ntsc_ranges[] = { | ||
274 | { 16 * 137.25 /*MHz*/, 0x8e, 0x14, }, | ||
275 | { 16 * 385.25 /*MHz*/, 0x8e, 0x12, }, | ||
276 | { 16 * 999.99 , 0x8e, 0x11, }, | ||
277 | }; | ||
278 | |||
279 | static struct tuner_params tuner_alps_tshc6_params[] = { | ||
280 | { | ||
281 | .type = TUNER_PARAM_TYPE_NTSC, | ||
282 | .ranges = tuner_alps_tshc6_ntsc_ranges, | ||
283 | .count = ARRAY_SIZE(tuner_alps_tshc6_ntsc_ranges), | ||
284 | }, | ||
285 | }; | ||
286 | |||
287 | /* ------------ TUNER_TEMIC_PAL_DK - TEMIC PAL ------------ */ | ||
288 | |||
289 | static struct tuner_range tuner_temic_pal_dk_ranges[] = { | ||
290 | { 16 * 168.25 /*MHz*/, 0x8e, 0xa0, }, | ||
291 | { 16 * 456.25 /*MHz*/, 0x8e, 0x90, }, | ||
292 | { 16 * 999.99 , 0x8e, 0x30, }, | ||
293 | }; | ||
294 | |||
295 | static struct tuner_params tuner_temic_pal_dk_params[] = { | ||
296 | { | ||
297 | .type = TUNER_PARAM_TYPE_PAL, | ||
298 | .ranges = tuner_temic_pal_dk_ranges, | ||
299 | .count = ARRAY_SIZE(tuner_temic_pal_dk_ranges), | ||
300 | }, | ||
301 | }; | ||
302 | |||
303 | /* ------------ TUNER_PHILIPS_NTSC_M - Philips NTSC ------------ */ | ||
304 | |||
305 | static struct tuner_range tuner_philips_ntsc_m_ranges[] = { | ||
306 | { 16 * 160.00 /*MHz*/, 0x8e, 0xa0, }, | ||
307 | { 16 * 454.00 /*MHz*/, 0x8e, 0x90, }, | ||
308 | { 16 * 999.99 , 0x8e, 0x30, }, | ||
309 | }; | ||
310 | |||
311 | static struct tuner_params tuner_philips_ntsc_m_params[] = { | ||
312 | { | ||
313 | .type = TUNER_PARAM_TYPE_NTSC, | ||
314 | .ranges = tuner_philips_ntsc_m_ranges, | ||
315 | .count = ARRAY_SIZE(tuner_philips_ntsc_m_ranges), | ||
316 | }, | ||
317 | }; | ||
318 | |||
319 | /* ------------ TUNER_TEMIC_4066FY5_PAL_I - TEMIC PAL_I ------------ */ | ||
320 | |||
321 | static struct tuner_range tuner_temic_40x6f_5_pal_ranges[] = { | ||
322 | { 16 * 169.00 /*MHz*/, 0x8e, 0xa0, }, | ||
323 | { 16 * 454.00 /*MHz*/, 0x8e, 0x90, }, | ||
324 | { 16 * 999.99 , 0x8e, 0x30, }, | ||
325 | }; | ||
326 | |||
327 | static struct tuner_params tuner_temic_4066fy5_pal_i_params[] = { | ||
328 | { | ||
329 | .type = TUNER_PARAM_TYPE_PAL, | ||
330 | .ranges = tuner_temic_40x6f_5_pal_ranges, | ||
331 | .count = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges), | ||
332 | }, | ||
333 | }; | ||
334 | |||
335 | /* ------------ TUNER_TEMIC_4006FN5_MULTI_PAL - TEMIC PAL ------------ */ | ||
336 | |||
337 | static struct tuner_params tuner_temic_4006fn5_multi_params[] = { | ||
338 | { | ||
339 | .type = TUNER_PARAM_TYPE_PAL, | ||
340 | .ranges = tuner_temic_40x6f_5_pal_ranges, | ||
341 | .count = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges), | ||
342 | }, | ||
343 | }; | ||
344 | |||
345 | /* 20-29 */ | ||
346 | /* ------------ TUNER_TEMIC_4009FR5_PAL - TEMIC PAL ------------ */ | ||
347 | |||
348 | static struct tuner_range tuner_temic_4009f_5_pal_ranges[] = { | ||
349 | { 16 * 141.00 /*MHz*/, 0x8e, 0xa0, }, | ||
350 | { 16 * 464.00 /*MHz*/, 0x8e, 0x90, }, | ||
351 | { 16 * 999.99 , 0x8e, 0x30, }, | ||
352 | }; | ||
353 | |||
354 | static struct tuner_params tuner_temic_4009f_5_params[] = { | ||
355 | { | ||
356 | .type = TUNER_PARAM_TYPE_PAL, | ||
357 | .ranges = tuner_temic_4009f_5_pal_ranges, | ||
358 | .count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges), | ||
359 | }, | ||
360 | }; | ||
361 | |||
362 | /* ------------ TUNER_TEMIC_4039FR5_NTSC - TEMIC NTSC ------------ */ | ||
363 | |||
364 | static struct tuner_range tuner_temic_4x3x_f_5_ntsc_ranges[] = { | ||
365 | { 16 * 158.00 /*MHz*/, 0x8e, 0xa0, }, | ||
366 | { 16 * 453.00 /*MHz*/, 0x8e, 0x90, }, | ||
367 | { 16 * 999.99 , 0x8e, 0x30, }, | ||
368 | }; | ||
369 | |||
370 | static struct tuner_params tuner_temic_4039fr5_params[] = { | ||
371 | { | ||
372 | .type = TUNER_PARAM_TYPE_NTSC, | ||
373 | .ranges = tuner_temic_4x3x_f_5_ntsc_ranges, | ||
374 | .count = ARRAY_SIZE(tuner_temic_4x3x_f_5_ntsc_ranges), | ||
375 | }, | ||
376 | }; | ||
377 | |||
378 | /* ------------ TUNER_TEMIC_4046FM5 - TEMIC PAL ------------ */ | ||
379 | |||
380 | static struct tuner_params tuner_temic_4046fm5_params[] = { | ||
381 | { | ||
382 | .type = TUNER_PARAM_TYPE_PAL, | ||
383 | .ranges = tuner_temic_40x6f_5_pal_ranges, | ||
384 | .count = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges), | ||
385 | }, | ||
386 | }; | ||
387 | |||
388 | /* ------------ TUNER_PHILIPS_PAL_DK - Philips PAL ------------ */ | ||
389 | |||
390 | static struct tuner_params tuner_philips_pal_dk_params[] = { | ||
391 | { | ||
392 | .type = TUNER_PARAM_TYPE_PAL, | ||
393 | .ranges = tuner_lg_pal_ranges, | ||
394 | .count = ARRAY_SIZE(tuner_lg_pal_ranges), | ||
395 | }, | ||
396 | }; | ||
397 | |||
398 | /* ------------ TUNER_PHILIPS_FQ1216ME - Philips PAL ------------ */ | ||
399 | |||
400 | static struct tuner_params tuner_philips_fq1216me_params[] = { | ||
401 | { | ||
402 | .type = TUNER_PARAM_TYPE_PAL, | ||
403 | .ranges = tuner_lg_pal_ranges, | ||
404 | .count = ARRAY_SIZE(tuner_lg_pal_ranges), | ||
405 | .has_tda9887 = 1, | ||
406 | .port1_active = 1, | ||
407 | .port2_active = 1, | ||
408 | .port2_invert_for_secam_lc = 1, | ||
409 | }, | ||
410 | }; | ||
411 | |||
412 | /* ------------ TUNER_LG_PAL_I_FM - LGINNOTEK PAL_I ------------ */ | ||
413 | |||
414 | static struct tuner_params tuner_lg_pal_i_fm_params[] = { | ||
415 | { | ||
416 | .type = TUNER_PARAM_TYPE_PAL, | ||
417 | .ranges = tuner_lg_pal_ranges, | ||
418 | .count = ARRAY_SIZE(tuner_lg_pal_ranges), | ||
419 | }, | ||
420 | }; | ||
421 | |||
422 | /* ------------ TUNER_LG_PAL_I - LGINNOTEK PAL_I ------------ */ | ||
423 | |||
424 | static struct tuner_params tuner_lg_pal_i_params[] = { | ||
425 | { | ||
426 | .type = TUNER_PARAM_TYPE_PAL, | ||
427 | .ranges = tuner_lg_pal_ranges, | ||
428 | .count = ARRAY_SIZE(tuner_lg_pal_ranges), | ||
429 | }, | ||
430 | }; | ||
431 | |||
432 | /* ------------ TUNER_LG_NTSC_FM - LGINNOTEK NTSC ------------ */ | ||
433 | |||
434 | static struct tuner_range tuner_lg_ntsc_fm_ranges[] = { | ||
435 | { 16 * 210.00 /*MHz*/, 0x8e, 0xa0, }, | ||
436 | { 16 * 497.00 /*MHz*/, 0x8e, 0x90, }, | ||
437 | { 16 * 999.99 , 0x8e, 0x30, }, | ||
438 | }; | ||
439 | |||
440 | static struct tuner_params tuner_lg_ntsc_fm_params[] = { | ||
441 | { | ||
442 | .type = TUNER_PARAM_TYPE_NTSC, | ||
443 | .ranges = tuner_lg_ntsc_fm_ranges, | ||
444 | .count = ARRAY_SIZE(tuner_lg_ntsc_fm_ranges), | ||
445 | }, | ||
446 | }; | ||
447 | |||
448 | /* ------------ TUNER_LG_PAL_FM - LGINNOTEK PAL ------------ */ | ||
449 | |||
450 | static struct tuner_params tuner_lg_pal_fm_params[] = { | ||
451 | { | ||
452 | .type = TUNER_PARAM_TYPE_PAL, | ||
453 | .ranges = tuner_lg_pal_ranges, | ||
454 | .count = ARRAY_SIZE(tuner_lg_pal_ranges), | ||
455 | }, | ||
456 | }; | ||
457 | |||
458 | /* ------------ TUNER_LG_PAL - LGINNOTEK PAL ------------ */ | ||
459 | |||
460 | static struct tuner_params tuner_lg_pal_params[] = { | ||
461 | { | ||
462 | .type = TUNER_PARAM_TYPE_PAL, | ||
463 | .ranges = tuner_lg_pal_ranges, | ||
464 | .count = ARRAY_SIZE(tuner_lg_pal_ranges), | ||
465 | }, | ||
466 | }; | ||
467 | |||
468 | /* 30-39 */ | ||
469 | /* ------------ TUNER_TEMIC_4009FN5_MULTI_PAL_FM - TEMIC PAL ------------ */ | ||
470 | |||
471 | static struct tuner_params tuner_temic_4009_fn5_multi_pal_fm_params[] = { | ||
472 | { | ||
473 | .type = TUNER_PARAM_TYPE_PAL, | ||
474 | .ranges = tuner_temic_4009f_5_pal_ranges, | ||
475 | .count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges), | ||
476 | }, | ||
477 | }; | ||
478 | |||
479 | /* ------------ TUNER_SHARP_2U5JF5540_NTSC - SHARP NTSC ------------ */ | ||
480 | |||
481 | static struct tuner_range tuner_sharp_2u5jf5540_ntsc_ranges[] = { | ||
482 | { 16 * 137.25 /*MHz*/, 0x8e, 0x01, }, | ||
483 | { 16 * 317.25 /*MHz*/, 0x8e, 0x02, }, | ||
484 | { 16 * 999.99 , 0x8e, 0x08, }, | ||
485 | }; | ||
486 | |||
487 | static struct tuner_params tuner_sharp_2u5jf5540_params[] = { | ||
488 | { | ||
489 | .type = TUNER_PARAM_TYPE_NTSC, | ||
490 | .ranges = tuner_sharp_2u5jf5540_ntsc_ranges, | ||
491 | .count = ARRAY_SIZE(tuner_sharp_2u5jf5540_ntsc_ranges), | ||
492 | }, | ||
493 | }; | ||
494 | |||
495 | /* ------------ TUNER_Samsung_PAL_TCPM9091PD27 - Samsung PAL ------------ */ | ||
496 | |||
497 | static struct tuner_range tuner_samsung_pal_tcpm9091pd27_ranges[] = { | ||
498 | { 16 * 169 /*MHz*/, 0x8e, 0xa0, }, | ||
499 | { 16 * 464 /*MHz*/, 0x8e, 0x90, }, | ||
500 | { 16 * 999.99 , 0x8e, 0x30, }, | ||
501 | }; | ||
502 | |||
503 | static struct tuner_params tuner_samsung_pal_tcpm9091pd27_params[] = { | ||
504 | { | ||
505 | .type = TUNER_PARAM_TYPE_PAL, | ||
506 | .ranges = tuner_samsung_pal_tcpm9091pd27_ranges, | ||
507 | .count = ARRAY_SIZE(tuner_samsung_pal_tcpm9091pd27_ranges), | ||
508 | }, | ||
509 | }; | ||
510 | |||
511 | /* ------------ TUNER_TEMIC_4106FH5 - TEMIC PAL ------------ */ | ||
512 | |||
513 | static struct tuner_params tuner_temic_4106fh5_params[] = { | ||
514 | { | ||
515 | .type = TUNER_PARAM_TYPE_PAL, | ||
516 | .ranges = tuner_temic_4009f_5_pal_ranges, | ||
517 | .count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges), | ||
518 | }, | ||
519 | }; | ||
520 | |||
521 | /* ------------ TUNER_TEMIC_4012FY5 - TEMIC PAL ------------ */ | ||
522 | |||
523 | static struct tuner_params tuner_temic_4012fy5_params[] = { | ||
524 | { | ||
525 | .type = TUNER_PARAM_TYPE_PAL, | ||
526 | .ranges = tuner_temic_pal_ranges, | ||
527 | .count = ARRAY_SIZE(tuner_temic_pal_ranges), | ||
528 | }, | ||
529 | }; | ||
530 | |||
531 | /* ------------ TUNER_TEMIC_4136FY5 - TEMIC NTSC ------------ */ | ||
532 | |||
533 | static struct tuner_params tuner_temic_4136_fy5_params[] = { | ||
534 | { | ||
535 | .type = TUNER_PARAM_TYPE_NTSC, | ||
536 | .ranges = tuner_temic_4x3x_f_5_ntsc_ranges, | ||
537 | .count = ARRAY_SIZE(tuner_temic_4x3x_f_5_ntsc_ranges), | ||
538 | }, | ||
539 | }; | ||
540 | |||
541 | /* ------------ TUNER_LG_PAL_NEW_TAPC - LGINNOTEK PAL ------------ */ | ||
542 | |||
543 | static struct tuner_range tuner_lg_new_tapc_ranges[] = { | ||
544 | { 16 * 170.00 /*MHz*/, 0x8e, 0x01, }, | ||
545 | { 16 * 450.00 /*MHz*/, 0x8e, 0x02, }, | ||
546 | { 16 * 999.99 , 0x8e, 0x08, }, | ||
547 | }; | ||
548 | |||
549 | static struct tuner_params tuner_lg_pal_new_tapc_params[] = { | ||
550 | { | ||
551 | .type = TUNER_PARAM_TYPE_PAL, | ||
552 | .ranges = tuner_lg_new_tapc_ranges, | ||
553 | .count = ARRAY_SIZE(tuner_lg_new_tapc_ranges), | ||
554 | }, | ||
555 | }; | ||
556 | |||
557 | /* ------------ TUNER_PHILIPS_FM1216ME_MK3 - Philips PAL ------------ */ | ||
558 | |||
559 | static struct tuner_range tuner_fm1216me_mk3_pal_ranges[] = { | ||
560 | { 16 * 158.00 /*MHz*/, 0x8e, 0x01, }, | ||
561 | { 16 * 442.00 /*MHz*/, 0x8e, 0x02, }, | ||
562 | { 16 * 999.99 , 0x8e, 0x04, }, | ||
563 | }; | ||
564 | |||
565 | static struct tuner_params tuner_fm1216me_mk3_params[] = { | ||
566 | { | ||
567 | .type = TUNER_PARAM_TYPE_PAL, | ||
568 | .ranges = tuner_fm1216me_mk3_pal_ranges, | ||
569 | .count = ARRAY_SIZE(tuner_fm1216me_mk3_pal_ranges), | ||
570 | .cb_first_if_lower_freq = 1, | ||
571 | .has_tda9887 = 1, | ||
572 | .port1_active = 1, | ||
573 | .port2_active = 1, | ||
574 | .port2_invert_for_secam_lc = 1, | ||
575 | .port1_fm_high_sensitivity = 1, | ||
576 | .default_top_mid = -2, | ||
577 | .default_top_secam_mid = -2, | ||
578 | .default_top_secam_high = -2, | ||
579 | }, | ||
580 | }; | ||
581 | |||
582 | /* ------------ TUNER_PHILIPS_FM1216MK5 - Philips PAL ------------ */ | ||
583 | |||
584 | static struct tuner_range tuner_fm1216mk5_pal_ranges[] = { | ||
585 | { 16 * 158.00 /*MHz*/, 0xce, 0x01, }, | ||
586 | { 16 * 441.00 /*MHz*/, 0xce, 0x02, }, | ||
587 | { 16 * 864.00 , 0xce, 0x04, }, | ||
588 | }; | ||
589 | |||
590 | static struct tuner_params tuner_fm1216mk5_params[] = { | ||
591 | { | ||
592 | .type = TUNER_PARAM_TYPE_PAL, | ||
593 | .ranges = tuner_fm1216mk5_pal_ranges, | ||
594 | .count = ARRAY_SIZE(tuner_fm1216mk5_pal_ranges), | ||
595 | .cb_first_if_lower_freq = 1, | ||
596 | .has_tda9887 = 1, | ||
597 | .port1_active = 1, | ||
598 | .port2_active = 1, | ||
599 | .port2_invert_for_secam_lc = 1, | ||
600 | .port1_fm_high_sensitivity = 1, | ||
601 | .default_top_mid = -2, | ||
602 | .default_top_secam_mid = -2, | ||
603 | .default_top_secam_high = -2, | ||
604 | }, | ||
605 | }; | ||
606 | |||
607 | /* ------------ TUNER_LG_NTSC_NEW_TAPC - LGINNOTEK NTSC ------------ */ | ||
608 | |||
609 | static struct tuner_params tuner_lg_ntsc_new_tapc_params[] = { | ||
610 | { | ||
611 | .type = TUNER_PARAM_TYPE_NTSC, | ||
612 | .ranges = tuner_lg_new_tapc_ranges, | ||
613 | .count = ARRAY_SIZE(tuner_lg_new_tapc_ranges), | ||
614 | }, | ||
615 | }; | ||
616 | |||
617 | /* 40-49 */ | ||
618 | /* ------------ TUNER_HITACHI_NTSC - HITACHI NTSC ------------ */ | ||
619 | |||
620 | static struct tuner_params tuner_hitachi_ntsc_params[] = { | ||
621 | { | ||
622 | .type = TUNER_PARAM_TYPE_NTSC, | ||
623 | .ranges = tuner_lg_new_tapc_ranges, | ||
624 | .count = ARRAY_SIZE(tuner_lg_new_tapc_ranges), | ||
625 | }, | ||
626 | }; | ||
627 | |||
628 | /* ------------ TUNER_PHILIPS_PAL_MK - Philips PAL ------------ */ | ||
629 | |||
630 | static struct tuner_range tuner_philips_pal_mk_pal_ranges[] = { | ||
631 | { 16 * 140.25 /*MHz*/, 0x8e, 0x01, }, | ||
632 | { 16 * 463.25 /*MHz*/, 0x8e, 0xc2, }, | ||
633 | { 16 * 999.99 , 0x8e, 0xcf, }, | ||
634 | }; | ||
635 | |||
636 | static struct tuner_params tuner_philips_pal_mk_params[] = { | ||
637 | { | ||
638 | .type = TUNER_PARAM_TYPE_PAL, | ||
639 | .ranges = tuner_philips_pal_mk_pal_ranges, | ||
640 | .count = ARRAY_SIZE(tuner_philips_pal_mk_pal_ranges), | ||
641 | }, | ||
642 | }; | ||
643 | |||
644 | /* ---- TUNER_PHILIPS_FCV1236D - Philips FCV1236D (ATSC/NTSC) ---- */ | ||
645 | |||
646 | static struct tuner_range tuner_philips_fcv1236d_ntsc_ranges[] = { | ||
647 | { 16 * 157.25 /*MHz*/, 0x8e, 0xa2, }, | ||
648 | { 16 * 451.25 /*MHz*/, 0x8e, 0x92, }, | ||
649 | { 16 * 999.99 , 0x8e, 0x32, }, | ||
650 | }; | ||
651 | |||
652 | static struct tuner_range tuner_philips_fcv1236d_atsc_ranges[] = { | ||
653 | { 16 * 159.00 /*MHz*/, 0x8e, 0xa0, }, | ||
654 | { 16 * 453.00 /*MHz*/, 0x8e, 0x90, }, | ||
655 | { 16 * 999.99 , 0x8e, 0x30, }, | ||
656 | }; | ||
657 | |||
658 | static struct tuner_params tuner_philips_fcv1236d_params[] = { | ||
659 | { | ||
660 | .type = TUNER_PARAM_TYPE_NTSC, | ||
661 | .ranges = tuner_philips_fcv1236d_ntsc_ranges, | ||
662 | .count = ARRAY_SIZE(tuner_philips_fcv1236d_ntsc_ranges), | ||
663 | }, | ||
664 | { | ||
665 | .type = TUNER_PARAM_TYPE_DIGITAL, | ||
666 | .ranges = tuner_philips_fcv1236d_atsc_ranges, | ||
667 | .count = ARRAY_SIZE(tuner_philips_fcv1236d_atsc_ranges), | ||
668 | .iffreq = 16 * 44.00, | ||
669 | }, | ||
670 | }; | ||
671 | |||
672 | /* ------------ TUNER_PHILIPS_FM1236_MK3 - Philips NTSC ------------ */ | ||
673 | |||
674 | static struct tuner_range tuner_fm1236_mk3_ntsc_ranges[] = { | ||
675 | { 16 * 160.00 /*MHz*/, 0x8e, 0x01, }, | ||
676 | { 16 * 442.00 /*MHz*/, 0x8e, 0x02, }, | ||
677 | { 16 * 999.99 , 0x8e, 0x04, }, | ||
678 | }; | ||
679 | |||
680 | static struct tuner_params tuner_fm1236_mk3_params[] = { | ||
681 | { | ||
682 | .type = TUNER_PARAM_TYPE_NTSC, | ||
683 | .ranges = tuner_fm1236_mk3_ntsc_ranges, | ||
684 | .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), | ||
685 | .cb_first_if_lower_freq = 1, | ||
686 | .has_tda9887 = 1, | ||
687 | .port1_active = 1, | ||
688 | .port2_active = 1, | ||
689 | .port1_fm_high_sensitivity = 1, | ||
690 | }, | ||
691 | }; | ||
692 | |||
693 | /* ------------ TUNER_PHILIPS_4IN1 - Philips NTSC ------------ */ | ||
694 | |||
695 | static struct tuner_params tuner_philips_4in1_params[] = { | ||
696 | { | ||
697 | .type = TUNER_PARAM_TYPE_NTSC, | ||
698 | .ranges = tuner_fm1236_mk3_ntsc_ranges, | ||
699 | .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), | ||
700 | }, | ||
701 | }; | ||
702 | |||
703 | /* ------------ TUNER_MICROTUNE_4049FM5 - Microtune PAL ------------ */ | ||
704 | |||
705 | static struct tuner_params tuner_microtune_4049_fm5_params[] = { | ||
706 | { | ||
707 | .type = TUNER_PARAM_TYPE_PAL, | ||
708 | .ranges = tuner_temic_4009f_5_pal_ranges, | ||
709 | .count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges), | ||
710 | .has_tda9887 = 1, | ||
711 | .port1_invert_for_secam_lc = 1, | ||
712 | .default_pll_gating_18 = 1, | ||
713 | .fm_gain_normal=1, | ||
714 | .radio_if = 1, /* 33.3 MHz */ | ||
715 | }, | ||
716 | }; | ||
717 | |||
718 | /* ------------ TUNER_PANASONIC_VP27 - Panasonic NTSC ------------ */ | ||
719 | |||
720 | static struct tuner_range tuner_panasonic_vp27_ntsc_ranges[] = { | ||
721 | { 16 * 160.00 /*MHz*/, 0xce, 0x01, }, | ||
722 | { 16 * 454.00 /*MHz*/, 0xce, 0x02, }, | ||
723 | { 16 * 999.99 , 0xce, 0x08, }, | ||
724 | }; | ||
725 | |||
726 | static struct tuner_params tuner_panasonic_vp27_params[] = { | ||
727 | { | ||
728 | .type = TUNER_PARAM_TYPE_NTSC, | ||
729 | .ranges = tuner_panasonic_vp27_ntsc_ranges, | ||
730 | .count = ARRAY_SIZE(tuner_panasonic_vp27_ntsc_ranges), | ||
731 | .has_tda9887 = 1, | ||
732 | .intercarrier_mode = 1, | ||
733 | .default_top_low = -3, | ||
734 | .default_top_mid = -3, | ||
735 | .default_top_high = -3, | ||
736 | }, | ||
737 | }; | ||
738 | |||
739 | /* ------------ TUNER_TNF_8831BGFF - Philips PAL ------------ */ | ||
740 | |||
741 | static struct tuner_range tuner_tnf_8831bgff_pal_ranges[] = { | ||
742 | { 16 * 161.25 /*MHz*/, 0x8e, 0xa0, }, | ||
743 | { 16 * 463.25 /*MHz*/, 0x8e, 0x90, }, | ||
744 | { 16 * 999.99 , 0x8e, 0x30, }, | ||
745 | }; | ||
746 | |||
747 | static struct tuner_params tuner_tnf_8831bgff_params[] = { | ||
748 | { | ||
749 | .type = TUNER_PARAM_TYPE_PAL, | ||
750 | .ranges = tuner_tnf_8831bgff_pal_ranges, | ||
751 | .count = ARRAY_SIZE(tuner_tnf_8831bgff_pal_ranges), | ||
752 | }, | ||
753 | }; | ||
754 | |||
755 | /* ------------ TUNER_MICROTUNE_4042FI5 - Microtune NTSC ------------ */ | ||
756 | |||
757 | static struct tuner_range tuner_microtune_4042fi5_ntsc_ranges[] = { | ||
758 | { 16 * 162.00 /*MHz*/, 0x8e, 0xa2, }, | ||
759 | { 16 * 457.00 /*MHz*/, 0x8e, 0x94, }, | ||
760 | { 16 * 999.99 , 0x8e, 0x31, }, | ||
761 | }; | ||
762 | |||
763 | static struct tuner_range tuner_microtune_4042fi5_atsc_ranges[] = { | ||
764 | { 16 * 162.00 /*MHz*/, 0x8e, 0xa1, }, | ||
765 | { 16 * 457.00 /*MHz*/, 0x8e, 0x91, }, | ||
766 | { 16 * 999.99 , 0x8e, 0x31, }, | ||
767 | }; | ||
768 | |||
769 | static struct tuner_params tuner_microtune_4042fi5_params[] = { | ||
770 | { | ||
771 | .type = TUNER_PARAM_TYPE_NTSC, | ||
772 | .ranges = tuner_microtune_4042fi5_ntsc_ranges, | ||
773 | .count = ARRAY_SIZE(tuner_microtune_4042fi5_ntsc_ranges), | ||
774 | }, | ||
775 | { | ||
776 | .type = TUNER_PARAM_TYPE_DIGITAL, | ||
777 | .ranges = tuner_microtune_4042fi5_atsc_ranges, | ||
778 | .count = ARRAY_SIZE(tuner_microtune_4042fi5_atsc_ranges), | ||
779 | .iffreq = 16 * 44.00 /*MHz*/, | ||
780 | }, | ||
781 | }; | ||
782 | |||
783 | /* 50-59 */ | ||
784 | /* ------------ TUNER_TCL_2002N - TCL NTSC ------------ */ | ||
785 | |||
786 | static struct tuner_range tuner_tcl_2002n_ntsc_ranges[] = { | ||
787 | { 16 * 172.00 /*MHz*/, 0x8e, 0x01, }, | ||
788 | { 16 * 448.00 /*MHz*/, 0x8e, 0x02, }, | ||
789 | { 16 * 999.99 , 0x8e, 0x08, }, | ||
790 | }; | ||
791 | |||
792 | static struct tuner_params tuner_tcl_2002n_params[] = { | ||
793 | { | ||
794 | .type = TUNER_PARAM_TYPE_NTSC, | ||
795 | .ranges = tuner_tcl_2002n_ntsc_ranges, | ||
796 | .count = ARRAY_SIZE(tuner_tcl_2002n_ntsc_ranges), | ||
797 | .cb_first_if_lower_freq = 1, | ||
798 | }, | ||
799 | }; | ||
800 | |||
801 | /* ------------ TUNER_PHILIPS_FM1256_IH3 - Philips PAL ------------ */ | ||
802 | |||
803 | static struct tuner_params tuner_philips_fm1256_ih3_params[] = { | ||
804 | { | ||
805 | .type = TUNER_PARAM_TYPE_PAL, | ||
806 | .ranges = tuner_fm1236_mk3_ntsc_ranges, | ||
807 | .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), | ||
808 | .radio_if = 1, /* 33.3 MHz */ | ||
809 | }, | ||
810 | }; | ||
811 | |||
812 | /* ------------ TUNER_THOMSON_DTT7610 - THOMSON ATSC ------------ */ | ||
813 | |||
814 | /* single range used for both ntsc and atsc */ | ||
815 | static struct tuner_range tuner_thomson_dtt7610_ntsc_ranges[] = { | ||
816 | { 16 * 157.25 /*MHz*/, 0x8e, 0x39, }, | ||
817 | { 16 * 454.00 /*MHz*/, 0x8e, 0x3a, }, | ||
818 | { 16 * 999.99 , 0x8e, 0x3c, }, | ||
819 | }; | ||
820 | |||
821 | static struct tuner_params tuner_thomson_dtt7610_params[] = { | ||
822 | { | ||
823 | .type = TUNER_PARAM_TYPE_NTSC, | ||
824 | .ranges = tuner_thomson_dtt7610_ntsc_ranges, | ||
825 | .count = ARRAY_SIZE(tuner_thomson_dtt7610_ntsc_ranges), | ||
826 | }, | ||
827 | { | ||
828 | .type = TUNER_PARAM_TYPE_DIGITAL, | ||
829 | .ranges = tuner_thomson_dtt7610_ntsc_ranges, | ||
830 | .count = ARRAY_SIZE(tuner_thomson_dtt7610_ntsc_ranges), | ||
831 | .iffreq = 16 * 44.00 /*MHz*/, | ||
832 | }, | ||
833 | }; | ||
834 | |||
835 | /* ------------ TUNER_PHILIPS_FQ1286 - Philips NTSC ------------ */ | ||
836 | |||
837 | static struct tuner_range tuner_philips_fq1286_ntsc_ranges[] = { | ||
838 | { 16 * 160.00 /*MHz*/, 0x8e, 0x41, }, | ||
839 | { 16 * 454.00 /*MHz*/, 0x8e, 0x42, }, | ||
840 | { 16 * 999.99 , 0x8e, 0x04, }, | ||
841 | }; | ||
842 | |||
843 | static struct tuner_params tuner_philips_fq1286_params[] = { | ||
844 | { | ||
845 | .type = TUNER_PARAM_TYPE_NTSC, | ||
846 | .ranges = tuner_philips_fq1286_ntsc_ranges, | ||
847 | .count = ARRAY_SIZE(tuner_philips_fq1286_ntsc_ranges), | ||
848 | }, | ||
849 | }; | ||
850 | |||
851 | /* ------------ TUNER_TCL_2002MB - TCL PAL ------------ */ | ||
852 | |||
853 | static struct tuner_range tuner_tcl_2002mb_pal_ranges[] = { | ||
854 | { 16 * 170.00 /*MHz*/, 0xce, 0x01, }, | ||
855 | { 16 * 450.00 /*MHz*/, 0xce, 0x02, }, | ||
856 | { 16 * 999.99 , 0xce, 0x08, }, | ||
857 | }; | ||
858 | |||
859 | static struct tuner_params tuner_tcl_2002mb_params[] = { | ||
860 | { | ||
861 | .type = TUNER_PARAM_TYPE_PAL, | ||
862 | .ranges = tuner_tcl_2002mb_pal_ranges, | ||
863 | .count = ARRAY_SIZE(tuner_tcl_2002mb_pal_ranges), | ||
864 | }, | ||
865 | }; | ||
866 | |||
867 | /* ------------ TUNER_PHILIPS_FQ1216AME_MK4 - Philips PAL ------------ */ | ||
868 | |||
869 | static struct tuner_range tuner_philips_fq12_6a___mk4_pal_ranges[] = { | ||
870 | { 16 * 160.00 /*MHz*/, 0xce, 0x01, }, | ||
871 | { 16 * 442.00 /*MHz*/, 0xce, 0x02, }, | ||
872 | { 16 * 999.99 , 0xce, 0x04, }, | ||
873 | }; | ||
874 | |||
875 | static struct tuner_params tuner_philips_fq1216ame_mk4_params[] = { | ||
876 | { | ||
877 | .type = TUNER_PARAM_TYPE_PAL, | ||
878 | .ranges = tuner_philips_fq12_6a___mk4_pal_ranges, | ||
879 | .count = ARRAY_SIZE(tuner_philips_fq12_6a___mk4_pal_ranges), | ||
880 | .has_tda9887 = 1, | ||
881 | .port1_active = 1, | ||
882 | .port2_invert_for_secam_lc = 1, | ||
883 | .default_top_mid = -2, | ||
884 | .default_top_secam_low = -2, | ||
885 | .default_top_secam_mid = -2, | ||
886 | .default_top_secam_high = -2, | ||
887 | }, | ||
888 | }; | ||
889 | |||
890 | /* ------------ TUNER_PHILIPS_FQ1236A_MK4 - Philips NTSC ------------ */ | ||
891 | |||
892 | static struct tuner_params tuner_philips_fq1236a_mk4_params[] = { | ||
893 | { | ||
894 | .type = TUNER_PARAM_TYPE_NTSC, | ||
895 | .ranges = tuner_fm1236_mk3_ntsc_ranges, | ||
896 | .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), | ||
897 | }, | ||
898 | }; | ||
899 | |||
900 | /* ------------ TUNER_YMEC_TVF_8531MF - Philips NTSC ------------ */ | ||
901 | |||
902 | static struct tuner_params tuner_ymec_tvf_8531mf_params[] = { | ||
903 | { | ||
904 | .type = TUNER_PARAM_TYPE_NTSC, | ||
905 | .ranges = tuner_philips_ntsc_m_ranges, | ||
906 | .count = ARRAY_SIZE(tuner_philips_ntsc_m_ranges), | ||
907 | }, | ||
908 | }; | ||
909 | |||
910 | /* ------------ TUNER_YMEC_TVF_5533MF - Philips NTSC ------------ */ | ||
911 | |||
912 | static struct tuner_range tuner_ymec_tvf_5533mf_ntsc_ranges[] = { | ||
913 | { 16 * 160.00 /*MHz*/, 0x8e, 0x01, }, | ||
914 | { 16 * 454.00 /*MHz*/, 0x8e, 0x02, }, | ||
915 | { 16 * 999.99 , 0x8e, 0x04, }, | ||
916 | }; | ||
917 | |||
918 | static struct tuner_params tuner_ymec_tvf_5533mf_params[] = { | ||
919 | { | ||
920 | .type = TUNER_PARAM_TYPE_NTSC, | ||
921 | .ranges = tuner_ymec_tvf_5533mf_ntsc_ranges, | ||
922 | .count = ARRAY_SIZE(tuner_ymec_tvf_5533mf_ntsc_ranges), | ||
923 | }, | ||
924 | }; | ||
925 | |||
926 | /* 60-69 */ | ||
927 | /* ------------ TUNER_THOMSON_DTT761X - THOMSON ATSC ------------ */ | ||
928 | /* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */ | ||
929 | |||
930 | static struct tuner_range tuner_thomson_dtt761x_ntsc_ranges[] = { | ||
931 | { 16 * 145.25 /*MHz*/, 0x8e, 0x39, }, | ||
932 | { 16 * 415.25 /*MHz*/, 0x8e, 0x3a, }, | ||
933 | { 16 * 999.99 , 0x8e, 0x3c, }, | ||
934 | }; | ||
935 | |||
936 | static struct tuner_range tuner_thomson_dtt761x_atsc_ranges[] = { | ||
937 | { 16 * 147.00 /*MHz*/, 0x8e, 0x39, }, | ||
938 | { 16 * 417.00 /*MHz*/, 0x8e, 0x3a, }, | ||
939 | { 16 * 999.99 , 0x8e, 0x3c, }, | ||
940 | }; | ||
941 | |||
942 | static struct tuner_params tuner_thomson_dtt761x_params[] = { | ||
943 | { | ||
944 | .type = TUNER_PARAM_TYPE_NTSC, | ||
945 | .ranges = tuner_thomson_dtt761x_ntsc_ranges, | ||
946 | .count = ARRAY_SIZE(tuner_thomson_dtt761x_ntsc_ranges), | ||
947 | .has_tda9887 = 1, | ||
948 | .fm_gain_normal = 1, | ||
949 | .radio_if = 2, /* 41.3 MHz */ | ||
950 | }, | ||
951 | { | ||
952 | .type = TUNER_PARAM_TYPE_DIGITAL, | ||
953 | .ranges = tuner_thomson_dtt761x_atsc_ranges, | ||
954 | .count = ARRAY_SIZE(tuner_thomson_dtt761x_atsc_ranges), | ||
955 | .iffreq = 16 * 44.00, /*MHz*/ | ||
956 | }, | ||
957 | }; | ||
958 | |||
959 | /* ------------ TUNER_TENA_9533_DI - Philips PAL ------------ */ | ||
960 | |||
961 | static struct tuner_range tuner_tena_9533_di_pal_ranges[] = { | ||
962 | { 16 * 160.25 /*MHz*/, 0x8e, 0x01, }, | ||
963 | { 16 * 464.25 /*MHz*/, 0x8e, 0x02, }, | ||
964 | { 16 * 999.99 , 0x8e, 0x04, }, | ||
965 | }; | ||
966 | |||
967 | static struct tuner_params tuner_tena_9533_di_params[] = { | ||
968 | { | ||
969 | .type = TUNER_PARAM_TYPE_PAL, | ||
970 | .ranges = tuner_tena_9533_di_pal_ranges, | ||
971 | .count = ARRAY_SIZE(tuner_tena_9533_di_pal_ranges), | ||
972 | }, | ||
973 | }; | ||
974 | |||
975 | /* ------------ TUNER_TENA_TNF_5337 - Tena tnf5337MFD STD M/N ------------ */ | ||
976 | |||
977 | static struct tuner_range tuner_tena_tnf_5337_ntsc_ranges[] = { | ||
978 | { 16 * 166.25 /*MHz*/, 0x86, 0x01, }, | ||
979 | { 16 * 466.25 /*MHz*/, 0x86, 0x02, }, | ||
980 | { 16 * 999.99 , 0x86, 0x08, }, | ||
981 | }; | ||
982 | |||
983 | static struct tuner_params tuner_tena_tnf_5337_params[] = { | ||
984 | { | ||
985 | .type = TUNER_PARAM_TYPE_NTSC, | ||
986 | .ranges = tuner_tena_tnf_5337_ntsc_ranges, | ||
987 | .count = ARRAY_SIZE(tuner_tena_tnf_5337_ntsc_ranges), | ||
988 | }, | ||
989 | }; | ||
990 | |||
991 | /* ------------ TUNER_PHILIPS_FMD1216ME(X)_MK3 - Philips PAL ------------ */ | ||
992 | |||
993 | static struct tuner_range tuner_philips_fmd1216me_mk3_pal_ranges[] = { | ||
994 | { 16 * 160.00 /*MHz*/, 0x86, 0x51, }, | ||
995 | { 16 * 442.00 /*MHz*/, 0x86, 0x52, }, | ||
996 | { 16 * 999.99 , 0x86, 0x54, }, | ||
997 | }; | ||
998 | |||
999 | static struct tuner_range tuner_philips_fmd1216me_mk3_dvb_ranges[] = { | ||
1000 | { 16 * 143.87 /*MHz*/, 0xbc, 0x41 }, | ||
1001 | { 16 * 158.87 /*MHz*/, 0xf4, 0x41 }, | ||
1002 | { 16 * 329.87 /*MHz*/, 0xbc, 0x42 }, | ||
1003 | { 16 * 441.87 /*MHz*/, 0xf4, 0x42 }, | ||
1004 | { 16 * 625.87 /*MHz*/, 0xbc, 0x44 }, | ||
1005 | { 16 * 803.87 /*MHz*/, 0xf4, 0x44 }, | ||
1006 | { 16 * 999.99 , 0xfc, 0x44 }, | ||
1007 | }; | ||
1008 | |||
1009 | static struct tuner_params tuner_philips_fmd1216me_mk3_params[] = { | ||
1010 | { | ||
1011 | .type = TUNER_PARAM_TYPE_PAL, | ||
1012 | .ranges = tuner_philips_fmd1216me_mk3_pal_ranges, | ||
1013 | .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_pal_ranges), | ||
1014 | .has_tda9887 = 1, | ||
1015 | .port1_active = 1, | ||
1016 | .port2_active = 1, | ||
1017 | .port2_fm_high_sensitivity = 1, | ||
1018 | .port2_invert_for_secam_lc = 1, | ||
1019 | .port1_set_for_fm_mono = 1, | ||
1020 | }, | ||
1021 | { | ||
1022 | .type = TUNER_PARAM_TYPE_DIGITAL, | ||
1023 | .ranges = tuner_philips_fmd1216me_mk3_dvb_ranges, | ||
1024 | .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_dvb_ranges), | ||
1025 | .iffreq = 16 * 36.125, /*MHz*/ | ||
1026 | }, | ||
1027 | }; | ||
1028 | |||
1029 | static struct tuner_params tuner_philips_fmd1216mex_mk3_params[] = { | ||
1030 | { | ||
1031 | .type = TUNER_PARAM_TYPE_PAL, | ||
1032 | .ranges = tuner_philips_fmd1216me_mk3_pal_ranges, | ||
1033 | .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_pal_ranges), | ||
1034 | .has_tda9887 = 1, | ||
1035 | .port1_active = 1, | ||
1036 | .port2_active = 1, | ||
1037 | .port2_fm_high_sensitivity = 1, | ||
1038 | .port2_invert_for_secam_lc = 1, | ||
1039 | .port1_set_for_fm_mono = 1, | ||
1040 | .radio_if = 1, | ||
1041 | .fm_gain_normal = 1, | ||
1042 | }, | ||
1043 | { | ||
1044 | .type = TUNER_PARAM_TYPE_DIGITAL, | ||
1045 | .ranges = tuner_philips_fmd1216me_mk3_dvb_ranges, | ||
1046 | .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_dvb_ranges), | ||
1047 | .iffreq = 16 * 36.125, /*MHz*/ | ||
1048 | }, | ||
1049 | }; | ||
1050 | |||
1051 | /* ------ TUNER_LG_TDVS_H06XF - LG INNOTEK / INFINEON ATSC ----- */ | ||
1052 | |||
1053 | static struct tuner_range tuner_tua6034_ntsc_ranges[] = { | ||
1054 | { 16 * 165.00 /*MHz*/, 0x8e, 0x01 }, | ||
1055 | { 16 * 450.00 /*MHz*/, 0x8e, 0x02 }, | ||
1056 | { 16 * 999.99 , 0x8e, 0x04 }, | ||
1057 | }; | ||
1058 | |||
1059 | static struct tuner_range tuner_tua6034_atsc_ranges[] = { | ||
1060 | { 16 * 165.00 /*MHz*/, 0xce, 0x01 }, | ||
1061 | { 16 * 450.00 /*MHz*/, 0xce, 0x02 }, | ||
1062 | { 16 * 999.99 , 0xce, 0x04 }, | ||
1063 | }; | ||
1064 | |||
1065 | static struct tuner_params tuner_lg_tdvs_h06xf_params[] = { | ||
1066 | { | ||
1067 | .type = TUNER_PARAM_TYPE_NTSC, | ||
1068 | .ranges = tuner_tua6034_ntsc_ranges, | ||
1069 | .count = ARRAY_SIZE(tuner_tua6034_ntsc_ranges), | ||
1070 | }, | ||
1071 | { | ||
1072 | .type = TUNER_PARAM_TYPE_DIGITAL, | ||
1073 | .ranges = tuner_tua6034_atsc_ranges, | ||
1074 | .count = ARRAY_SIZE(tuner_tua6034_atsc_ranges), | ||
1075 | .iffreq = 16 * 44.00, | ||
1076 | }, | ||
1077 | }; | ||
1078 | |||
1079 | /* ------------ TUNER_YMEC_TVF66T5_B_DFF - Philips PAL ------------ */ | ||
1080 | |||
1081 | static struct tuner_range tuner_ymec_tvf66t5_b_dff_pal_ranges[] = { | ||
1082 | { 16 * 160.25 /*MHz*/, 0x8e, 0x01, }, | ||
1083 | { 16 * 464.25 /*MHz*/, 0x8e, 0x02, }, | ||
1084 | { 16 * 999.99 , 0x8e, 0x08, }, | ||
1085 | }; | ||
1086 | |||
1087 | static struct tuner_params tuner_ymec_tvf66t5_b_dff_params[] = { | ||
1088 | { | ||
1089 | .type = TUNER_PARAM_TYPE_PAL, | ||
1090 | .ranges = tuner_ymec_tvf66t5_b_dff_pal_ranges, | ||
1091 | .count = ARRAY_SIZE(tuner_ymec_tvf66t5_b_dff_pal_ranges), | ||
1092 | }, | ||
1093 | }; | ||
1094 | |||
1095 | /* ------------ TUNER_LG_NTSC_TALN_MINI - LGINNOTEK NTSC ------------ */ | ||
1096 | |||
1097 | static struct tuner_range tuner_lg_taln_ntsc_ranges[] = { | ||
1098 | { 16 * 137.25 /*MHz*/, 0x8e, 0x01, }, | ||
1099 | { 16 * 373.25 /*MHz*/, 0x8e, 0x02, }, | ||
1100 | { 16 * 999.99 , 0x8e, 0x08, }, | ||
1101 | }; | ||
1102 | |||
1103 | static struct tuner_range tuner_lg_taln_pal_secam_ranges[] = { | ||
1104 | { 16 * 150.00 /*MHz*/, 0x8e, 0x01, }, | ||
1105 | { 16 * 425.00 /*MHz*/, 0x8e, 0x02, }, | ||
1106 | { 16 * 999.99 , 0x8e, 0x08, }, | ||
1107 | }; | ||
1108 | |||
1109 | static struct tuner_params tuner_lg_taln_params[] = { | ||
1110 | { | ||
1111 | .type = TUNER_PARAM_TYPE_NTSC, | ||
1112 | .ranges = tuner_lg_taln_ntsc_ranges, | ||
1113 | .count = ARRAY_SIZE(tuner_lg_taln_ntsc_ranges), | ||
1114 | },{ | ||
1115 | .type = TUNER_PARAM_TYPE_PAL, | ||
1116 | .ranges = tuner_lg_taln_pal_secam_ranges, | ||
1117 | .count = ARRAY_SIZE(tuner_lg_taln_pal_secam_ranges), | ||
1118 | }, | ||
1119 | }; | ||
1120 | |||
1121 | /* ------------ TUNER_PHILIPS_TD1316 - Philips PAL ------------ */ | ||
1122 | |||
1123 | static struct tuner_range tuner_philips_td1316_pal_ranges[] = { | ||
1124 | { 16 * 160.00 /*MHz*/, 0xc8, 0xa1, }, | ||
1125 | { 16 * 442.00 /*MHz*/, 0xc8, 0xa2, }, | ||
1126 | { 16 * 999.99 , 0xc8, 0xa4, }, | ||
1127 | }; | ||
1128 | |||
1129 | static struct tuner_range tuner_philips_td1316_dvb_ranges[] = { | ||
1130 | { 16 * 93.834 /*MHz*/, 0xca, 0x60, }, | ||
1131 | { 16 * 123.834 /*MHz*/, 0xca, 0xa0, }, | ||
1132 | { 16 * 163.834 /*MHz*/, 0xca, 0xc0, }, | ||
1133 | { 16 * 253.834 /*MHz*/, 0xca, 0x60, }, | ||
1134 | { 16 * 383.834 /*MHz*/, 0xca, 0xa0, }, | ||
1135 | { 16 * 443.834 /*MHz*/, 0xca, 0xc0, }, | ||
1136 | { 16 * 583.834 /*MHz*/, 0xca, 0x60, }, | ||
1137 | { 16 * 793.834 /*MHz*/, 0xca, 0xa0, }, | ||
1138 | { 16 * 999.999 , 0xca, 0xe0, }, | ||
1139 | }; | ||
1140 | |||
1141 | static struct tuner_params tuner_philips_td1316_params[] = { | ||
1142 | { | ||
1143 | .type = TUNER_PARAM_TYPE_PAL, | ||
1144 | .ranges = tuner_philips_td1316_pal_ranges, | ||
1145 | .count = ARRAY_SIZE(tuner_philips_td1316_pal_ranges), | ||
1146 | }, | ||
1147 | { | ||
1148 | .type = TUNER_PARAM_TYPE_DIGITAL, | ||
1149 | .ranges = tuner_philips_td1316_dvb_ranges, | ||
1150 | .count = ARRAY_SIZE(tuner_philips_td1316_dvb_ranges), | ||
1151 | .iffreq = 16 * 36.166667 /*MHz*/, | ||
1152 | }, | ||
1153 | }; | ||
1154 | |||
1155 | /* ------------ TUNER_PHILIPS_TUV1236D - Philips ATSC ------------ */ | ||
1156 | |||
1157 | static struct tuner_range tuner_tuv1236d_ntsc_ranges[] = { | ||
1158 | { 16 * 157.25 /*MHz*/, 0xce, 0x01, }, | ||
1159 | { 16 * 454.00 /*MHz*/, 0xce, 0x02, }, | ||
1160 | { 16 * 999.99 , 0xce, 0x04, }, | ||
1161 | }; | ||
1162 | |||
1163 | static struct tuner_range tuner_tuv1236d_atsc_ranges[] = { | ||
1164 | { 16 * 157.25 /*MHz*/, 0xc6, 0x41, }, | ||
1165 | { 16 * 454.00 /*MHz*/, 0xc6, 0x42, }, | ||
1166 | { 16 * 999.99 , 0xc6, 0x44, }, | ||
1167 | }; | ||
1168 | |||
1169 | static struct tuner_params tuner_tuv1236d_params[] = { | ||
1170 | { | ||
1171 | .type = TUNER_PARAM_TYPE_NTSC, | ||
1172 | .ranges = tuner_tuv1236d_ntsc_ranges, | ||
1173 | .count = ARRAY_SIZE(tuner_tuv1236d_ntsc_ranges), | ||
1174 | }, | ||
1175 | { | ||
1176 | .type = TUNER_PARAM_TYPE_DIGITAL, | ||
1177 | .ranges = tuner_tuv1236d_atsc_ranges, | ||
1178 | .count = ARRAY_SIZE(tuner_tuv1236d_atsc_ranges), | ||
1179 | .iffreq = 16 * 44.00, | ||
1180 | }, | ||
1181 | }; | ||
1182 | |||
1183 | /* ------------ TUNER_TNF_xxx5 - Texas Instruments--------- */ | ||
1184 | /* This is known to work with Tenna TVF58t5-MFF and TVF5835 MFF | ||
1185 | * but it is expected to work also with other Tenna/Ymec | ||
1186 | * models based on TI SN 761677 chip on both PAL and NTSC | ||
1187 | */ | ||
1188 | |||
1189 | static struct tuner_range tuner_tnf_5335_d_if_pal_ranges[] = { | ||
1190 | { 16 * 168.25 /*MHz*/, 0x8e, 0x01, }, | ||
1191 | { 16 * 471.25 /*MHz*/, 0x8e, 0x02, }, | ||
1192 | { 16 * 999.99 , 0x8e, 0x08, }, | ||
1193 | }; | ||
1194 | |||
1195 | static struct tuner_range tuner_tnf_5335mf_ntsc_ranges[] = { | ||
1196 | { 16 * 169.25 /*MHz*/, 0x8e, 0x01, }, | ||
1197 | { 16 * 469.25 /*MHz*/, 0x8e, 0x02, }, | ||
1198 | { 16 * 999.99 , 0x8e, 0x08, }, | ||
1199 | }; | ||
1200 | |||
1201 | static struct tuner_params tuner_tnf_5335mf_params[] = { | ||
1202 | { | ||
1203 | .type = TUNER_PARAM_TYPE_NTSC, | ||
1204 | .ranges = tuner_tnf_5335mf_ntsc_ranges, | ||
1205 | .count = ARRAY_SIZE(tuner_tnf_5335mf_ntsc_ranges), | ||
1206 | }, | ||
1207 | { | ||
1208 | .type = TUNER_PARAM_TYPE_PAL, | ||
1209 | .ranges = tuner_tnf_5335_d_if_pal_ranges, | ||
1210 | .count = ARRAY_SIZE(tuner_tnf_5335_d_if_pal_ranges), | ||
1211 | }, | ||
1212 | }; | ||
1213 | |||
1214 | /* 70-79 */ | ||
1215 | /* ------------ TUNER_SAMSUNG_TCPN_2121P30A - Samsung NTSC ------------ */ | ||
1216 | |||
1217 | /* '+ 4' turns on the Low Noise Amplifier */ | ||
1218 | static struct tuner_range tuner_samsung_tcpn_2121p30a_ntsc_ranges[] = { | ||
1219 | { 16 * 130.00 /*MHz*/, 0xce, 0x01 + 4, }, | ||
1220 | { 16 * 364.50 /*MHz*/, 0xce, 0x02 + 4, }, | ||
1221 | { 16 * 999.99 , 0xce, 0x08 + 4, }, | ||
1222 | }; | ||
1223 | |||
1224 | static struct tuner_params tuner_samsung_tcpn_2121p30a_params[] = { | ||
1225 | { | ||
1226 | .type = TUNER_PARAM_TYPE_NTSC, | ||
1227 | .ranges = tuner_samsung_tcpn_2121p30a_ntsc_ranges, | ||
1228 | .count = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_ntsc_ranges), | ||
1229 | }, | ||
1230 | }; | ||
1231 | |||
1232 | /* ------------ TUNER_THOMSON_FE6600 - DViCO Hybrid PAL ------------ */ | ||
1233 | |||
1234 | static struct tuner_range tuner_thomson_fe6600_pal_ranges[] = { | ||
1235 | { 16 * 160.00 /*MHz*/, 0xfe, 0x11, }, | ||
1236 | { 16 * 442.00 /*MHz*/, 0xf6, 0x12, }, | ||
1237 | { 16 * 999.99 , 0xf6, 0x18, }, | ||
1238 | }; | ||
1239 | |||
1240 | static struct tuner_range tuner_thomson_fe6600_dvb_ranges[] = { | ||
1241 | { 16 * 250.00 /*MHz*/, 0xb4, 0x12, }, | ||
1242 | { 16 * 455.00 /*MHz*/, 0xfe, 0x11, }, | ||
1243 | { 16 * 775.50 /*MHz*/, 0xbc, 0x18, }, | ||
1244 | { 16 * 999.99 , 0xf4, 0x18, }, | ||
1245 | }; | ||
1246 | |||
1247 | static struct tuner_params tuner_thomson_fe6600_params[] = { | ||
1248 | { | ||
1249 | .type = TUNER_PARAM_TYPE_PAL, | ||
1250 | .ranges = tuner_thomson_fe6600_pal_ranges, | ||
1251 | .count = ARRAY_SIZE(tuner_thomson_fe6600_pal_ranges), | ||
1252 | }, | ||
1253 | { | ||
1254 | .type = TUNER_PARAM_TYPE_DIGITAL, | ||
1255 | .ranges = tuner_thomson_fe6600_dvb_ranges, | ||
1256 | .count = ARRAY_SIZE(tuner_thomson_fe6600_dvb_ranges), | ||
1257 | .iffreq = 16 * 36.125 /*MHz*/, | ||
1258 | }, | ||
1259 | }; | ||
1260 | |||
1261 | /* ------------ TUNER_SAMSUNG_TCPG_6121P30A - Samsung PAL ------------ */ | ||
1262 | |||
1263 | /* '+ 4' turns on the Low Noise Amplifier */ | ||
1264 | static struct tuner_range tuner_samsung_tcpg_6121p30a_pal_ranges[] = { | ||
1265 | { 16 * 146.25 /*MHz*/, 0xce, 0x01 + 4, }, | ||
1266 | { 16 * 428.50 /*MHz*/, 0xce, 0x02 + 4, }, | ||
1267 | { 16 * 999.99 , 0xce, 0x08 + 4, }, | ||
1268 | }; | ||
1269 | |||
1270 | static struct tuner_params tuner_samsung_tcpg_6121p30a_params[] = { | ||
1271 | { | ||
1272 | .type = TUNER_PARAM_TYPE_PAL, | ||
1273 | .ranges = tuner_samsung_tcpg_6121p30a_pal_ranges, | ||
1274 | .count = ARRAY_SIZE(tuner_samsung_tcpg_6121p30a_pal_ranges), | ||
1275 | .has_tda9887 = 1, | ||
1276 | .port1_active = 1, | ||
1277 | .port2_active = 1, | ||
1278 | .port2_invert_for_secam_lc = 1, | ||
1279 | }, | ||
1280 | }; | ||
1281 | |||
1282 | /* ------------ TUNER_TCL_MF02GIP-5N-E - TCL MF02GIP-5N ------------ */ | ||
1283 | |||
1284 | static struct tuner_range tuner_tcl_mf02gip_5n_ntsc_ranges[] = { | ||
1285 | { 16 * 172.00 /*MHz*/, 0x8e, 0x01, }, | ||
1286 | { 16 * 448.00 /*MHz*/, 0x8e, 0x02, }, | ||
1287 | { 16 * 999.99 , 0x8e, 0x04, }, | ||
1288 | }; | ||
1289 | |||
1290 | static struct tuner_params tuner_tcl_mf02gip_5n_params[] = { | ||
1291 | { | ||
1292 | .type = TUNER_PARAM_TYPE_NTSC, | ||
1293 | .ranges = tuner_tcl_mf02gip_5n_ntsc_ranges, | ||
1294 | .count = ARRAY_SIZE(tuner_tcl_mf02gip_5n_ntsc_ranges), | ||
1295 | .cb_first_if_lower_freq = 1, | ||
1296 | }, | ||
1297 | }; | ||
1298 | |||
1299 | /* 80-89 */ | ||
1300 | /* --------- TUNER_PHILIPS_FQ1216LME_MK3 -- active loopthrough, no FM ------- */ | ||
1301 | |||
1302 | static struct tuner_params tuner_fq1216lme_mk3_params[] = { | ||
1303 | { | ||
1304 | .type = TUNER_PARAM_TYPE_PAL, | ||
1305 | .ranges = tuner_fm1216me_mk3_pal_ranges, | ||
1306 | .count = ARRAY_SIZE(tuner_fm1216me_mk3_pal_ranges), | ||
1307 | .cb_first_if_lower_freq = 1, /* not specified, but safe to do */ | ||
1308 | .has_tda9887 = 1, /* TDA9886 */ | ||
1309 | .port1_active = 1, | ||
1310 | .port2_active = 1, | ||
1311 | .port2_invert_for_secam_lc = 1, | ||
1312 | .default_top_low = 4, | ||
1313 | .default_top_mid = 4, | ||
1314 | .default_top_high = 4, | ||
1315 | .default_top_secam_low = 4, | ||
1316 | .default_top_secam_mid = 4, | ||
1317 | .default_top_secam_high = 4, | ||
1318 | }, | ||
1319 | }; | ||
1320 | |||
1321 | /* ----- TUNER_PARTSNIC_PTI_5NF05 - Partsnic (Daewoo) PTI-5NF05 NTSC ----- */ | ||
1322 | |||
1323 | static struct tuner_range tuner_partsnic_pti_5nf05_ranges[] = { | ||
1324 | /* The datasheet specified channel ranges and the bandswitch byte */ | ||
1325 | /* The control byte value of 0x8e is just a guess */ | ||
1326 | { 16 * 133.25 /*MHz*/, 0x8e, 0x01, }, /* Channels 2 - B */ | ||
1327 | { 16 * 367.25 /*MHz*/, 0x8e, 0x02, }, /* Channels C - W+11 */ | ||
1328 | { 16 * 999.99 , 0x8e, 0x08, }, /* Channels W+12 - 69 */ | ||
1329 | }; | ||
1330 | |||
1331 | static struct tuner_params tuner_partsnic_pti_5nf05_params[] = { | ||
1332 | { | ||
1333 | .type = TUNER_PARAM_TYPE_NTSC, | ||
1334 | .ranges = tuner_partsnic_pti_5nf05_ranges, | ||
1335 | .count = ARRAY_SIZE(tuner_partsnic_pti_5nf05_ranges), | ||
1336 | .cb_first_if_lower_freq = 1, /* not specified but safe to do */ | ||
1337 | }, | ||
1338 | }; | ||
1339 | |||
1340 | /* --------- TUNER_PHILIPS_CU1216L - DVB-C NIM ------------------------- */ | ||
1341 | |||
1342 | static struct tuner_range tuner_cu1216l_ranges[] = { | ||
1343 | { 16 * 160.25 /*MHz*/, 0xce, 0x01 }, | ||
1344 | { 16 * 444.25 /*MHz*/, 0xce, 0x02 }, | ||
1345 | { 16 * 999.99 , 0xce, 0x04 }, | ||
1346 | }; | ||
1347 | |||
1348 | static struct tuner_params tuner_philips_cu1216l_params[] = { | ||
1349 | { | ||
1350 | .type = TUNER_PARAM_TYPE_DIGITAL, | ||
1351 | .ranges = tuner_cu1216l_ranges, | ||
1352 | .count = ARRAY_SIZE(tuner_cu1216l_ranges), | ||
1353 | .iffreq = 16 * 36.125, /*MHz*/ | ||
1354 | }, | ||
1355 | }; | ||
1356 | |||
1357 | /* ---------------------- TUNER_SONY_BTF_PXN01Z ------------------------ */ | ||
1358 | |||
1359 | static struct tuner_range tuner_sony_btf_pxn01z_ranges[] = { | ||
1360 | { 16 * 137.25 /*MHz*/, 0x8e, 0x01, }, | ||
1361 | { 16 * 367.25 /*MHz*/, 0x8e, 0x02, }, | ||
1362 | { 16 * 999.99 , 0x8e, 0x04, }, | ||
1363 | }; | ||
1364 | |||
1365 | static struct tuner_params tuner_sony_btf_pxn01z_params[] = { | ||
1366 | { | ||
1367 | .type = TUNER_PARAM_TYPE_NTSC, | ||
1368 | .ranges = tuner_sony_btf_pxn01z_ranges, | ||
1369 | .count = ARRAY_SIZE(tuner_sony_btf_pxn01z_ranges), | ||
1370 | }, | ||
1371 | }; | ||
1372 | |||
1373 | /* ------------ TUNER_PHILIPS_FQ1236_MK5 - Philips NTSC ------------ */ | ||
1374 | |||
1375 | static struct tuner_params tuner_philips_fq1236_mk5_params[] = { | ||
1376 | { | ||
1377 | .type = TUNER_PARAM_TYPE_NTSC, | ||
1378 | .ranges = tuner_fm1236_mk3_ntsc_ranges, | ||
1379 | .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), | ||
1380 | .has_tda9887 = 1, /* TDA9885, no FM radio */ | ||
1381 | }, | ||
1382 | }; | ||
1383 | |||
1384 | /* --------------------------------------------------------------------- */ | ||
1385 | |||
1386 | struct tunertype tuners[] = { | ||
1387 | /* 0-9 */ | ||
1388 | [TUNER_TEMIC_PAL] = { /* TEMIC PAL */ | ||
1389 | .name = "Temic PAL (4002 FH5)", | ||
1390 | .params = tuner_temic_pal_params, | ||
1391 | .count = ARRAY_SIZE(tuner_temic_pal_params), | ||
1392 | }, | ||
1393 | [TUNER_PHILIPS_PAL_I] = { /* Philips PAL_I */ | ||
1394 | .name = "Philips PAL_I (FI1246 and compatibles)", | ||
1395 | .params = tuner_philips_pal_i_params, | ||
1396 | .count = ARRAY_SIZE(tuner_philips_pal_i_params), | ||
1397 | }, | ||
1398 | [TUNER_PHILIPS_NTSC] = { /* Philips NTSC */ | ||
1399 | .name = "Philips NTSC (FI1236,FM1236 and compatibles)", | ||
1400 | .params = tuner_philips_ntsc_params, | ||
1401 | .count = ARRAY_SIZE(tuner_philips_ntsc_params), | ||
1402 | }, | ||
1403 | [TUNER_PHILIPS_SECAM] = { /* Philips SECAM */ | ||
1404 | .name = "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)", | ||
1405 | .params = tuner_philips_secam_params, | ||
1406 | .count = ARRAY_SIZE(tuner_philips_secam_params), | ||
1407 | }, | ||
1408 | [TUNER_ABSENT] = { /* Tuner Absent */ | ||
1409 | .name = "NoTuner", | ||
1410 | }, | ||
1411 | [TUNER_PHILIPS_PAL] = { /* Philips PAL */ | ||
1412 | .name = "Philips PAL_BG (FI1216 and compatibles)", | ||
1413 | .params = tuner_philips_pal_params, | ||
1414 | .count = ARRAY_SIZE(tuner_philips_pal_params), | ||
1415 | }, | ||
1416 | [TUNER_TEMIC_NTSC] = { /* TEMIC NTSC */ | ||
1417 | .name = "Temic NTSC (4032 FY5)", | ||
1418 | .params = tuner_temic_ntsc_params, | ||
1419 | .count = ARRAY_SIZE(tuner_temic_ntsc_params), | ||
1420 | }, | ||
1421 | [TUNER_TEMIC_PAL_I] = { /* TEMIC PAL_I */ | ||
1422 | .name = "Temic PAL_I (4062 FY5)", | ||
1423 | .params = tuner_temic_pal_i_params, | ||
1424 | .count = ARRAY_SIZE(tuner_temic_pal_i_params), | ||
1425 | }, | ||
1426 | [TUNER_TEMIC_4036FY5_NTSC] = { /* TEMIC NTSC */ | ||
1427 | .name = "Temic NTSC (4036 FY5)", | ||
1428 | .params = tuner_temic_4036fy5_ntsc_params, | ||
1429 | .count = ARRAY_SIZE(tuner_temic_4036fy5_ntsc_params), | ||
1430 | }, | ||
1431 | [TUNER_ALPS_TSBH1_NTSC] = { /* TEMIC NTSC */ | ||
1432 | .name = "Alps HSBH1", | ||
1433 | .params = tuner_alps_tsbh1_ntsc_params, | ||
1434 | .count = ARRAY_SIZE(tuner_alps_tsbh1_ntsc_params), | ||
1435 | }, | ||
1436 | |||
1437 | /* 10-19 */ | ||
1438 | [TUNER_ALPS_TSBE1_PAL] = { /* TEMIC PAL */ | ||
1439 | .name = "Alps TSBE1", | ||
1440 | .params = tuner_alps_tsb_1_params, | ||
1441 | .count = ARRAY_SIZE(tuner_alps_tsb_1_params), | ||
1442 | }, | ||
1443 | [TUNER_ALPS_TSBB5_PAL_I] = { /* Alps PAL_I */ | ||
1444 | .name = "Alps TSBB5", | ||
1445 | .params = tuner_alps_tsbb5_params, | ||
1446 | .count = ARRAY_SIZE(tuner_alps_tsbb5_params), | ||
1447 | }, | ||
1448 | [TUNER_ALPS_TSBE5_PAL] = { /* Alps PAL */ | ||
1449 | .name = "Alps TSBE5", | ||
1450 | .params = tuner_alps_tsbe5_params, | ||
1451 | .count = ARRAY_SIZE(tuner_alps_tsbe5_params), | ||
1452 | }, | ||
1453 | [TUNER_ALPS_TSBC5_PAL] = { /* Alps PAL */ | ||
1454 | .name = "Alps TSBC5", | ||
1455 | .params = tuner_alps_tsbc5_params, | ||
1456 | .count = ARRAY_SIZE(tuner_alps_tsbc5_params), | ||
1457 | }, | ||
1458 | [TUNER_TEMIC_4006FH5_PAL] = { /* TEMIC PAL */ | ||
1459 | .name = "Temic PAL_BG (4006FH5)", | ||
1460 | .params = tuner_temic_4006fh5_params, | ||
1461 | .count = ARRAY_SIZE(tuner_temic_4006fh5_params), | ||
1462 | }, | ||
1463 | [TUNER_ALPS_TSHC6_NTSC] = { /* Alps NTSC */ | ||
1464 | .name = "Alps TSCH6", | ||
1465 | .params = tuner_alps_tshc6_params, | ||
1466 | .count = ARRAY_SIZE(tuner_alps_tshc6_params), | ||
1467 | }, | ||
1468 | [TUNER_TEMIC_PAL_DK] = { /* TEMIC PAL */ | ||
1469 | .name = "Temic PAL_DK (4016 FY5)", | ||
1470 | .params = tuner_temic_pal_dk_params, | ||
1471 | .count = ARRAY_SIZE(tuner_temic_pal_dk_params), | ||
1472 | }, | ||
1473 | [TUNER_PHILIPS_NTSC_M] = { /* Philips NTSC */ | ||
1474 | .name = "Philips NTSC_M (MK2)", | ||
1475 | .params = tuner_philips_ntsc_m_params, | ||
1476 | .count = ARRAY_SIZE(tuner_philips_ntsc_m_params), | ||
1477 | }, | ||
1478 | [TUNER_TEMIC_4066FY5_PAL_I] = { /* TEMIC PAL_I */ | ||
1479 | .name = "Temic PAL_I (4066 FY5)", | ||
1480 | .params = tuner_temic_4066fy5_pal_i_params, | ||
1481 | .count = ARRAY_SIZE(tuner_temic_4066fy5_pal_i_params), | ||
1482 | }, | ||
1483 | [TUNER_TEMIC_4006FN5_MULTI_PAL] = { /* TEMIC PAL */ | ||
1484 | .name = "Temic PAL* auto (4006 FN5)", | ||
1485 | .params = tuner_temic_4006fn5_multi_params, | ||
1486 | .count = ARRAY_SIZE(tuner_temic_4006fn5_multi_params), | ||
1487 | }, | ||
1488 | |||
1489 | /* 20-29 */ | ||
1490 | [TUNER_TEMIC_4009FR5_PAL] = { /* TEMIC PAL */ | ||
1491 | .name = "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)", | ||
1492 | .params = tuner_temic_4009f_5_params, | ||
1493 | .count = ARRAY_SIZE(tuner_temic_4009f_5_params), | ||
1494 | }, | ||
1495 | [TUNER_TEMIC_4039FR5_NTSC] = { /* TEMIC NTSC */ | ||
1496 | .name = "Temic NTSC (4039 FR5)", | ||
1497 | .params = tuner_temic_4039fr5_params, | ||
1498 | .count = ARRAY_SIZE(tuner_temic_4039fr5_params), | ||
1499 | }, | ||
1500 | [TUNER_TEMIC_4046FM5] = { /* TEMIC PAL */ | ||
1501 | .name = "Temic PAL/SECAM multi (4046 FM5)", | ||
1502 | .params = tuner_temic_4046fm5_params, | ||
1503 | .count = ARRAY_SIZE(tuner_temic_4046fm5_params), | ||
1504 | }, | ||
1505 | [TUNER_PHILIPS_PAL_DK] = { /* Philips PAL */ | ||
1506 | .name = "Philips PAL_DK (FI1256 and compatibles)", | ||
1507 | .params = tuner_philips_pal_dk_params, | ||
1508 | .count = ARRAY_SIZE(tuner_philips_pal_dk_params), | ||
1509 | }, | ||
1510 | [TUNER_PHILIPS_FQ1216ME] = { /* Philips PAL */ | ||
1511 | .name = "Philips PAL/SECAM multi (FQ1216ME)", | ||
1512 | .params = tuner_philips_fq1216me_params, | ||
1513 | .count = ARRAY_SIZE(tuner_philips_fq1216me_params), | ||
1514 | }, | ||
1515 | [TUNER_LG_PAL_I_FM] = { /* LGINNOTEK PAL_I */ | ||
1516 | .name = "LG PAL_I+FM (TAPC-I001D)", | ||
1517 | .params = tuner_lg_pal_i_fm_params, | ||
1518 | .count = ARRAY_SIZE(tuner_lg_pal_i_fm_params), | ||
1519 | }, | ||
1520 | [TUNER_LG_PAL_I] = { /* LGINNOTEK PAL_I */ | ||
1521 | .name = "LG PAL_I (TAPC-I701D)", | ||
1522 | .params = tuner_lg_pal_i_params, | ||
1523 | .count = ARRAY_SIZE(tuner_lg_pal_i_params), | ||
1524 | }, | ||
1525 | [TUNER_LG_NTSC_FM] = { /* LGINNOTEK NTSC */ | ||
1526 | .name = "LG NTSC+FM (TPI8NSR01F)", | ||
1527 | .params = tuner_lg_ntsc_fm_params, | ||
1528 | .count = ARRAY_SIZE(tuner_lg_ntsc_fm_params), | ||
1529 | }, | ||
1530 | [TUNER_LG_PAL_FM] = { /* LGINNOTEK PAL */ | ||
1531 | .name = "LG PAL_BG+FM (TPI8PSB01D)", | ||
1532 | .params = tuner_lg_pal_fm_params, | ||
1533 | .count = ARRAY_SIZE(tuner_lg_pal_fm_params), | ||
1534 | }, | ||
1535 | [TUNER_LG_PAL] = { /* LGINNOTEK PAL */ | ||
1536 | .name = "LG PAL_BG (TPI8PSB11D)", | ||
1537 | .params = tuner_lg_pal_params, | ||
1538 | .count = ARRAY_SIZE(tuner_lg_pal_params), | ||
1539 | }, | ||
1540 | |||
1541 | /* 30-39 */ | ||
1542 | [TUNER_TEMIC_4009FN5_MULTI_PAL_FM] = { /* TEMIC PAL */ | ||
1543 | .name = "Temic PAL* auto + FM (4009 FN5)", | ||
1544 | .params = tuner_temic_4009_fn5_multi_pal_fm_params, | ||
1545 | .count = ARRAY_SIZE(tuner_temic_4009_fn5_multi_pal_fm_params), | ||
1546 | }, | ||
1547 | [TUNER_SHARP_2U5JF5540_NTSC] = { /* SHARP NTSC */ | ||
1548 | .name = "SHARP NTSC_JP (2U5JF5540)", | ||
1549 | .params = tuner_sharp_2u5jf5540_params, | ||
1550 | .count = ARRAY_SIZE(tuner_sharp_2u5jf5540_params), | ||
1551 | }, | ||
1552 | [TUNER_Samsung_PAL_TCPM9091PD27] = { /* Samsung PAL */ | ||
1553 | .name = "Samsung PAL TCPM9091PD27", | ||
1554 | .params = tuner_samsung_pal_tcpm9091pd27_params, | ||
1555 | .count = ARRAY_SIZE(tuner_samsung_pal_tcpm9091pd27_params), | ||
1556 | }, | ||
1557 | [TUNER_MT2032] = { /* Microtune PAL|NTSC */ | ||
1558 | .name = "MT20xx universal", | ||
1559 | /* see mt20xx.c for details */ }, | ||
1560 | [TUNER_TEMIC_4106FH5] = { /* TEMIC PAL */ | ||
1561 | .name = "Temic PAL_BG (4106 FH5)", | ||
1562 | .params = tuner_temic_4106fh5_params, | ||
1563 | .count = ARRAY_SIZE(tuner_temic_4106fh5_params), | ||
1564 | }, | ||
1565 | [TUNER_TEMIC_4012FY5] = { /* TEMIC PAL */ | ||
1566 | .name = "Temic PAL_DK/SECAM_L (4012 FY5)", | ||
1567 | .params = tuner_temic_4012fy5_params, | ||
1568 | .count = ARRAY_SIZE(tuner_temic_4012fy5_params), | ||
1569 | }, | ||
1570 | [TUNER_TEMIC_4136FY5] = { /* TEMIC NTSC */ | ||
1571 | .name = "Temic NTSC (4136 FY5)", | ||
1572 | .params = tuner_temic_4136_fy5_params, | ||
1573 | .count = ARRAY_SIZE(tuner_temic_4136_fy5_params), | ||
1574 | }, | ||
1575 | [TUNER_LG_PAL_NEW_TAPC] = { /* LGINNOTEK PAL */ | ||
1576 | .name = "LG PAL (newer TAPC series)", | ||
1577 | .params = tuner_lg_pal_new_tapc_params, | ||
1578 | .count = ARRAY_SIZE(tuner_lg_pal_new_tapc_params), | ||
1579 | }, | ||
1580 | [TUNER_PHILIPS_FM1216ME_MK3] = { /* Philips PAL */ | ||
1581 | .name = "Philips PAL/SECAM multi (FM1216ME MK3)", | ||
1582 | .params = tuner_fm1216me_mk3_params, | ||
1583 | .count = ARRAY_SIZE(tuner_fm1216me_mk3_params), | ||
1584 | }, | ||
1585 | [TUNER_LG_NTSC_NEW_TAPC] = { /* LGINNOTEK NTSC */ | ||
1586 | .name = "LG NTSC (newer TAPC series)", | ||
1587 | .params = tuner_lg_ntsc_new_tapc_params, | ||
1588 | .count = ARRAY_SIZE(tuner_lg_ntsc_new_tapc_params), | ||
1589 | }, | ||
1590 | |||
1591 | /* 40-49 */ | ||
1592 | [TUNER_HITACHI_NTSC] = { /* HITACHI NTSC */ | ||
1593 | .name = "HITACHI V7-J180AT", | ||
1594 | .params = tuner_hitachi_ntsc_params, | ||
1595 | .count = ARRAY_SIZE(tuner_hitachi_ntsc_params), | ||
1596 | }, | ||
1597 | [TUNER_PHILIPS_PAL_MK] = { /* Philips PAL */ | ||
1598 | .name = "Philips PAL_MK (FI1216 MK)", | ||
1599 | .params = tuner_philips_pal_mk_params, | ||
1600 | .count = ARRAY_SIZE(tuner_philips_pal_mk_params), | ||
1601 | }, | ||
1602 | [TUNER_PHILIPS_FCV1236D] = { /* Philips ATSC */ | ||
1603 | .name = "Philips FCV1236D ATSC/NTSC dual in", | ||
1604 | .params = tuner_philips_fcv1236d_params, | ||
1605 | .count = ARRAY_SIZE(tuner_philips_fcv1236d_params), | ||
1606 | .min = 16 * 53.00, | ||
1607 | .max = 16 * 803.00, | ||
1608 | .stepsize = 62500, | ||
1609 | }, | ||
1610 | [TUNER_PHILIPS_FM1236_MK3] = { /* Philips NTSC */ | ||
1611 | .name = "Philips NTSC MK3 (FM1236MK3 or FM1236/F)", | ||
1612 | .params = tuner_fm1236_mk3_params, | ||
1613 | .count = ARRAY_SIZE(tuner_fm1236_mk3_params), | ||
1614 | }, | ||
1615 | [TUNER_PHILIPS_4IN1] = { /* Philips NTSC */ | ||
1616 | .name = "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)", | ||
1617 | .params = tuner_philips_4in1_params, | ||
1618 | .count = ARRAY_SIZE(tuner_philips_4in1_params), | ||
1619 | }, | ||
1620 | [TUNER_MICROTUNE_4049FM5] = { /* Microtune PAL */ | ||
1621 | .name = "Microtune 4049 FM5", | ||
1622 | .params = tuner_microtune_4049_fm5_params, | ||
1623 | .count = ARRAY_SIZE(tuner_microtune_4049_fm5_params), | ||
1624 | }, | ||
1625 | [TUNER_PANASONIC_VP27] = { /* Panasonic NTSC */ | ||
1626 | .name = "Panasonic VP27s/ENGE4324D", | ||
1627 | .params = tuner_panasonic_vp27_params, | ||
1628 | .count = ARRAY_SIZE(tuner_panasonic_vp27_params), | ||
1629 | }, | ||
1630 | [TUNER_LG_NTSC_TAPE] = { /* LGINNOTEK NTSC */ | ||
1631 | .name = "LG NTSC (TAPE series)", | ||
1632 | .params = tuner_fm1236_mk3_params, | ||
1633 | .count = ARRAY_SIZE(tuner_fm1236_mk3_params), | ||
1634 | }, | ||
1635 | [TUNER_TNF_8831BGFF] = { /* Philips PAL */ | ||
1636 | .name = "Tenna TNF 8831 BGFF)", | ||
1637 | .params = tuner_tnf_8831bgff_params, | ||
1638 | .count = ARRAY_SIZE(tuner_tnf_8831bgff_params), | ||
1639 | }, | ||
1640 | [TUNER_MICROTUNE_4042FI5] = { /* Microtune NTSC */ | ||
1641 | .name = "Microtune 4042 FI5 ATSC/NTSC dual in", | ||
1642 | .params = tuner_microtune_4042fi5_params, | ||
1643 | .count = ARRAY_SIZE(tuner_microtune_4042fi5_params), | ||
1644 | .min = 16 * 57.00, | ||
1645 | .max = 16 * 858.00, | ||
1646 | .stepsize = 62500, | ||
1647 | }, | ||
1648 | |||
1649 | /* 50-59 */ | ||
1650 | [TUNER_TCL_2002N] = { /* TCL NTSC */ | ||
1651 | .name = "TCL 2002N", | ||
1652 | .params = tuner_tcl_2002n_params, | ||
1653 | .count = ARRAY_SIZE(tuner_tcl_2002n_params), | ||
1654 | }, | ||
1655 | [TUNER_PHILIPS_FM1256_IH3] = { /* Philips PAL */ | ||
1656 | .name = "Philips PAL/SECAM_D (FM 1256 I-H3)", | ||
1657 | .params = tuner_philips_fm1256_ih3_params, | ||
1658 | .count = ARRAY_SIZE(tuner_philips_fm1256_ih3_params), | ||
1659 | }, | ||
1660 | [TUNER_THOMSON_DTT7610] = { /* THOMSON ATSC */ | ||
1661 | .name = "Thomson DTT 7610 (ATSC/NTSC)", | ||
1662 | .params = tuner_thomson_dtt7610_params, | ||
1663 | .count = ARRAY_SIZE(tuner_thomson_dtt7610_params), | ||
1664 | .min = 16 * 44.00, | ||
1665 | .max = 16 * 958.00, | ||
1666 | .stepsize = 62500, | ||
1667 | }, | ||
1668 | [TUNER_PHILIPS_FQ1286] = { /* Philips NTSC */ | ||
1669 | .name = "Philips FQ1286", | ||
1670 | .params = tuner_philips_fq1286_params, | ||
1671 | .count = ARRAY_SIZE(tuner_philips_fq1286_params), | ||
1672 | }, | ||
1673 | [TUNER_PHILIPS_TDA8290] = { /* Philips PAL|NTSC */ | ||
1674 | .name = "Philips/NXP TDA 8290/8295 + 8275/8275A/18271", | ||
1675 | /* see tda8290.c for details */ }, | ||
1676 | [TUNER_TCL_2002MB] = { /* TCL PAL */ | ||
1677 | .name = "TCL 2002MB", | ||
1678 | .params = tuner_tcl_2002mb_params, | ||
1679 | .count = ARRAY_SIZE(tuner_tcl_2002mb_params), | ||
1680 | }, | ||
1681 | [TUNER_PHILIPS_FQ1216AME_MK4] = { /* Philips PAL */ | ||
1682 | .name = "Philips PAL/SECAM multi (FQ1216AME MK4)", | ||
1683 | .params = tuner_philips_fq1216ame_mk4_params, | ||
1684 | .count = ARRAY_SIZE(tuner_philips_fq1216ame_mk4_params), | ||
1685 | }, | ||
1686 | [TUNER_PHILIPS_FQ1236A_MK4] = { /* Philips NTSC */ | ||
1687 | .name = "Philips FQ1236A MK4", | ||
1688 | .params = tuner_philips_fq1236a_mk4_params, | ||
1689 | .count = ARRAY_SIZE(tuner_philips_fq1236a_mk4_params), | ||
1690 | }, | ||
1691 | [TUNER_YMEC_TVF_8531MF] = { /* Philips NTSC */ | ||
1692 | .name = "Ymec TVision TVF-8531MF/8831MF/8731MF", | ||
1693 | .params = tuner_ymec_tvf_8531mf_params, | ||
1694 | .count = ARRAY_SIZE(tuner_ymec_tvf_8531mf_params), | ||
1695 | }, | ||
1696 | [TUNER_YMEC_TVF_5533MF] = { /* Philips NTSC */ | ||
1697 | .name = "Ymec TVision TVF-5533MF", | ||
1698 | .params = tuner_ymec_tvf_5533mf_params, | ||
1699 | .count = ARRAY_SIZE(tuner_ymec_tvf_5533mf_params), | ||
1700 | }, | ||
1701 | |||
1702 | /* 60-69 */ | ||
1703 | [TUNER_THOMSON_DTT761X] = { /* THOMSON ATSC */ | ||
1704 | /* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */ | ||
1705 | .name = "Thomson DTT 761X (ATSC/NTSC)", | ||
1706 | .params = tuner_thomson_dtt761x_params, | ||
1707 | .count = ARRAY_SIZE(tuner_thomson_dtt761x_params), | ||
1708 | .min = 16 * 57.00, | ||
1709 | .max = 16 * 863.00, | ||
1710 | .stepsize = 62500, | ||
1711 | .initdata = tua603x_agc103, | ||
1712 | }, | ||
1713 | [TUNER_TENA_9533_DI] = { /* Philips PAL */ | ||
1714 | .name = "Tena TNF9533-D/IF/TNF9533-B/DF", | ||
1715 | .params = tuner_tena_9533_di_params, | ||
1716 | .count = ARRAY_SIZE(tuner_tena_9533_di_params), | ||
1717 | }, | ||
1718 | [TUNER_TEA5767] = { /* Philips RADIO */ | ||
1719 | .name = "Philips TEA5767HN FM Radio", | ||
1720 | /* see tea5767.c for details */ | ||
1721 | }, | ||
1722 | [TUNER_PHILIPS_FMD1216ME_MK3] = { /* Philips PAL */ | ||
1723 | .name = "Philips FMD1216ME MK3 Hybrid Tuner", | ||
1724 | .params = tuner_philips_fmd1216me_mk3_params, | ||
1725 | .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_params), | ||
1726 | .min = 16 * 50.87, | ||
1727 | .max = 16 * 858.00, | ||
1728 | .stepsize = 166667, | ||
1729 | .initdata = tua603x_agc112, | ||
1730 | .sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 }, | ||
1731 | }, | ||
1732 | [TUNER_LG_TDVS_H06XF] = { /* LGINNOTEK ATSC */ | ||
1733 | .name = "LG TDVS-H06xF", /* H061F, H062F & H064F */ | ||
1734 | .params = tuner_lg_tdvs_h06xf_params, | ||
1735 | .count = ARRAY_SIZE(tuner_lg_tdvs_h06xf_params), | ||
1736 | .min = 16 * 54.00, | ||
1737 | .max = 16 * 863.00, | ||
1738 | .stepsize = 62500, | ||
1739 | .initdata = tua603x_agc103, | ||
1740 | }, | ||
1741 | [TUNER_YMEC_TVF66T5_B_DFF] = { /* Philips PAL */ | ||
1742 | .name = "Ymec TVF66T5-B/DFF", | ||
1743 | .params = tuner_ymec_tvf66t5_b_dff_params, | ||
1744 | .count = ARRAY_SIZE(tuner_ymec_tvf66t5_b_dff_params), | ||
1745 | }, | ||
1746 | [TUNER_LG_TALN] = { /* LGINNOTEK NTSC / PAL / SECAM */ | ||
1747 | .name = "LG TALN series", | ||
1748 | .params = tuner_lg_taln_params, | ||
1749 | .count = ARRAY_SIZE(tuner_lg_taln_params), | ||
1750 | }, | ||
1751 | [TUNER_PHILIPS_TD1316] = { /* Philips PAL */ | ||
1752 | .name = "Philips TD1316 Hybrid Tuner", | ||
1753 | .params = tuner_philips_td1316_params, | ||
1754 | .count = ARRAY_SIZE(tuner_philips_td1316_params), | ||
1755 | .min = 16 * 87.00, | ||
1756 | .max = 16 * 895.00, | ||
1757 | .stepsize = 166667, | ||
1758 | }, | ||
1759 | [TUNER_PHILIPS_TUV1236D] = { /* Philips ATSC */ | ||
1760 | .name = "Philips TUV1236D ATSC/NTSC dual in", | ||
1761 | .params = tuner_tuv1236d_params, | ||
1762 | .count = ARRAY_SIZE(tuner_tuv1236d_params), | ||
1763 | .min = 16 * 54.00, | ||
1764 | .max = 16 * 864.00, | ||
1765 | .stepsize = 62500, | ||
1766 | }, | ||
1767 | [TUNER_TNF_5335MF] = { /* Tenna PAL/NTSC */ | ||
1768 | .name = "Tena TNF 5335 and similar models", | ||
1769 | .params = tuner_tnf_5335mf_params, | ||
1770 | .count = ARRAY_SIZE(tuner_tnf_5335mf_params), | ||
1771 | }, | ||
1772 | |||
1773 | /* 70-79 */ | ||
1774 | [TUNER_SAMSUNG_TCPN_2121P30A] = { /* Samsung NTSC */ | ||
1775 | .name = "Samsung TCPN 2121P30A", | ||
1776 | .params = tuner_samsung_tcpn_2121p30a_params, | ||
1777 | .count = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_params), | ||
1778 | }, | ||
1779 | [TUNER_XC2028] = { /* Xceive 2028 */ | ||
1780 | .name = "Xceive xc2028/xc3028 tuner", | ||
1781 | /* see tuner-xc2028.c for details */ | ||
1782 | }, | ||
1783 | [TUNER_THOMSON_FE6600] = { /* Thomson PAL / DVB-T */ | ||
1784 | .name = "Thomson FE6600", | ||
1785 | .params = tuner_thomson_fe6600_params, | ||
1786 | .count = ARRAY_SIZE(tuner_thomson_fe6600_params), | ||
1787 | .min = 16 * 44.25, | ||
1788 | .max = 16 * 858.00, | ||
1789 | .stepsize = 166667, | ||
1790 | }, | ||
1791 | [TUNER_SAMSUNG_TCPG_6121P30A] = { /* Samsung PAL */ | ||
1792 | .name = "Samsung TCPG 6121P30A", | ||
1793 | .params = tuner_samsung_tcpg_6121p30a_params, | ||
1794 | .count = ARRAY_SIZE(tuner_samsung_tcpg_6121p30a_params), | ||
1795 | }, | ||
1796 | [TUNER_TDA9887] = { /* Philips TDA 9887 IF PLL Demodulator. | ||
1797 | This chip is part of some modern tuners */ | ||
1798 | .name = "Philips TDA988[5,6,7] IF PLL Demodulator", | ||
1799 | /* see tda9887.c for details */ | ||
1800 | }, | ||
1801 | [TUNER_TEA5761] = { /* Philips RADIO */ | ||
1802 | .name = "Philips TEA5761 FM Radio", | ||
1803 | /* see tea5767.c for details */ | ||
1804 | }, | ||
1805 | [TUNER_XC5000] = { /* Xceive 5000 */ | ||
1806 | .name = "Xceive 5000 tuner", | ||
1807 | /* see xc5000.c for details */ | ||
1808 | }, | ||
1809 | [TUNER_XC4000] = { /* Xceive 4000 */ | ||
1810 | .name = "Xceive 4000 tuner", | ||
1811 | /* see xc4000.c for details */ | ||
1812 | }, | ||
1813 | [TUNER_TCL_MF02GIP_5N] = { /* TCL tuner MF02GIP-5N-E */ | ||
1814 | .name = "TCL tuner MF02GIP-5N-E", | ||
1815 | .params = tuner_tcl_mf02gip_5n_params, | ||
1816 | .count = ARRAY_SIZE(tuner_tcl_mf02gip_5n_params), | ||
1817 | }, | ||
1818 | [TUNER_PHILIPS_FMD1216MEX_MK3] = { /* Philips PAL */ | ||
1819 | .name = "Philips FMD1216MEX MK3 Hybrid Tuner", | ||
1820 | .params = tuner_philips_fmd1216mex_mk3_params, | ||
1821 | .count = ARRAY_SIZE(tuner_philips_fmd1216mex_mk3_params), | ||
1822 | .min = 16 * 50.87, | ||
1823 | .max = 16 * 858.00, | ||
1824 | .stepsize = 166667, | ||
1825 | .initdata = tua603x_agc112, | ||
1826 | .sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 }, | ||
1827 | }, | ||
1828 | [TUNER_PHILIPS_FM1216MK5] = { /* Philips PAL */ | ||
1829 | .name = "Philips PAL/SECAM multi (FM1216 MK5)", | ||
1830 | .params = tuner_fm1216mk5_params, | ||
1831 | .count = ARRAY_SIZE(tuner_fm1216mk5_params), | ||
1832 | }, | ||
1833 | |||
1834 | /* 80-89 */ | ||
1835 | [TUNER_PHILIPS_FQ1216LME_MK3] = { /* PAL/SECAM, Loop-thru, no FM */ | ||
1836 | .name = "Philips FQ1216LME MK3 PAL/SECAM w/active loopthrough", | ||
1837 | .params = tuner_fq1216lme_mk3_params, | ||
1838 | .count = ARRAY_SIZE(tuner_fq1216lme_mk3_params), | ||
1839 | }, | ||
1840 | |||
1841 | [TUNER_PARTSNIC_PTI_5NF05] = { | ||
1842 | .name = "Partsnic (Daewoo) PTI-5NF05", | ||
1843 | .params = tuner_partsnic_pti_5nf05_params, | ||
1844 | .count = ARRAY_SIZE(tuner_partsnic_pti_5nf05_params), | ||
1845 | }, | ||
1846 | [TUNER_PHILIPS_CU1216L] = { | ||
1847 | .name = "Philips CU1216L", | ||
1848 | .params = tuner_philips_cu1216l_params, | ||
1849 | .count = ARRAY_SIZE(tuner_philips_cu1216l_params), | ||
1850 | .stepsize = 62500, | ||
1851 | }, | ||
1852 | [TUNER_NXP_TDA18271] = { | ||
1853 | .name = "NXP TDA18271", | ||
1854 | /* see tda18271-fe.c for details */ | ||
1855 | }, | ||
1856 | [TUNER_SONY_BTF_PXN01Z] = { | ||
1857 | .name = "Sony BTF-Pxn01Z", | ||
1858 | .params = tuner_sony_btf_pxn01z_params, | ||
1859 | .count = ARRAY_SIZE(tuner_sony_btf_pxn01z_params), | ||
1860 | }, | ||
1861 | [TUNER_PHILIPS_FQ1236_MK5] = { /* NTSC, TDA9885, no FM radio */ | ||
1862 | .name = "Philips FQ1236 MK5", | ||
1863 | .params = tuner_philips_fq1236_mk5_params, | ||
1864 | .count = ARRAY_SIZE(tuner_philips_fq1236_mk5_params), | ||
1865 | }, | ||
1866 | [TUNER_TENA_TNF_5337] = { /* Tena 5337 MFD */ | ||
1867 | .name = "Tena TNF5337 MFD", | ||
1868 | .params = tuner_tena_tnf_5337_params, | ||
1869 | .count = ARRAY_SIZE(tuner_tena_tnf_5337_params), | ||
1870 | }, | ||
1871 | [TUNER_XC5000C] = { /* Xceive 5000C */ | ||
1872 | .name = "Xceive 5000C tuner", | ||
1873 | /* see xc5000.c for details */ | ||
1874 | }, | ||
1875 | }; | ||
1876 | EXPORT_SYMBOL(tuners); | ||
1877 | |||
1878 | unsigned const int tuner_count = ARRAY_SIZE(tuners); | ||
1879 | EXPORT_SYMBOL(tuner_count); | ||
1880 | |||
1881 | MODULE_DESCRIPTION("Simple tuner device type database"); | ||
1882 | MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer"); | ||
1883 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/tuners/tuner-xc2028-types.h b/drivers/media/tuners/tuner-xc2028-types.h new file mode 100644 index 000000000000..74dc46a71f64 --- /dev/null +++ b/drivers/media/tuners/tuner-xc2028-types.h | |||
@@ -0,0 +1,141 @@ | |||
1 | /* tuner-xc2028_types | ||
2 | * | ||
3 | * This file includes internal tipes to be used inside tuner-xc2028. | ||
4 | * Shouldn't be included outside tuner-xc2028 | ||
5 | * | ||
6 | * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org) | ||
7 | * This code is placed under the terms of the GNU General Public License v2 | ||
8 | */ | ||
9 | |||
10 | /* xc3028 firmware types */ | ||
11 | |||
12 | /* BASE firmware should be loaded before any other firmware */ | ||
13 | #define BASE (1<<0) | ||
14 | #define BASE_TYPES (BASE|F8MHZ|MTS|FM|INPUT1|INPUT2|INIT1) | ||
15 | |||
16 | /* F8MHZ marks BASE firmwares for 8 MHz Bandwidth */ | ||
17 | #define F8MHZ (1<<1) | ||
18 | |||
19 | /* Multichannel Television Sound (MTS) | ||
20 | Those firmwares are capable of using xc2038 DSP to decode audio and | ||
21 | produce a baseband audio output on some pins of the chip. | ||
22 | There are MTS firmwares for the most used video standards. It should be | ||
23 | required to use MTS firmwares, depending on the way audio is routed into | ||
24 | the bridge chip | ||
25 | */ | ||
26 | #define MTS (1<<2) | ||
27 | |||
28 | /* FIXME: I have no idea what's the difference between | ||
29 | D2620 and D2633 firmwares | ||
30 | */ | ||
31 | #define D2620 (1<<3) | ||
32 | #define D2633 (1<<4) | ||
33 | |||
34 | /* DTV firmwares for 6, 7 and 8 MHz | ||
35 | DTV6 - 6MHz - ATSC/DVB-C/DVB-T/ISDB-T/DOCSIS | ||
36 | DTV8 - 8MHz - DVB-C/DVB-T | ||
37 | */ | ||
38 | #define DTV6 (1 << 5) | ||
39 | #define QAM (1 << 6) | ||
40 | #define DTV7 (1<<7) | ||
41 | #define DTV78 (1<<8) | ||
42 | #define DTV8 (1<<9) | ||
43 | |||
44 | #define DTV_TYPES (D2620|D2633|DTV6|QAM|DTV7|DTV78|DTV8|ATSC) | ||
45 | |||
46 | /* There's a FM | BASE firmware + FM specific firmware (std=0) */ | ||
47 | #define FM (1<<10) | ||
48 | |||
49 | #define STD_SPECIFIC_TYPES (MTS|FM|LCD|NOGD) | ||
50 | |||
51 | /* Applies only for FM firmware | ||
52 | Makes it use RF input 1 (pin #2) instead of input 2 (pin #4) | ||
53 | */ | ||
54 | #define INPUT1 (1<<11) | ||
55 | |||
56 | |||
57 | /* LCD firmwares exist only for MTS STD/MN (PAL or NTSC/M) | ||
58 | and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr) | ||
59 | There are variants both with and without NOGD | ||
60 | Those firmwares produce better result with LCD displays | ||
61 | */ | ||
62 | #define LCD (1<<12) | ||
63 | |||
64 | /* NOGD firmwares exist only for MTS STD/MN (PAL or NTSC/M) | ||
65 | and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr) | ||
66 | The NOGD firmwares don't have group delay compensation filter | ||
67 | */ | ||
68 | #define NOGD (1<<13) | ||
69 | |||
70 | /* Old firmwares were broken into init0 and init1 */ | ||
71 | #define INIT1 (1<<14) | ||
72 | |||
73 | /* SCODE firmware selects particular behaviours */ | ||
74 | #define MONO (1 << 15) | ||
75 | #define ATSC (1 << 16) | ||
76 | #define IF (1 << 17) | ||
77 | #define LG60 (1 << 18) | ||
78 | #define ATI638 (1 << 19) | ||
79 | #define OREN538 (1 << 20) | ||
80 | #define OREN36 (1 << 21) | ||
81 | #define TOYOTA388 (1 << 22) | ||
82 | #define TOYOTA794 (1 << 23) | ||
83 | #define DIBCOM52 (1 << 24) | ||
84 | #define ZARLINK456 (1 << 25) | ||
85 | #define CHINA (1 << 26) | ||
86 | #define F6MHZ (1 << 27) | ||
87 | #define INPUT2 (1 << 28) | ||
88 | #define SCODE (1 << 29) | ||
89 | |||
90 | /* This flag identifies that the scode table has a new format */ | ||
91 | #define HAS_IF (1 << 30) | ||
92 | |||
93 | /* There are different scode tables for MTS and non-MTS. | ||
94 | The MTS firmwares support mono only | ||
95 | */ | ||
96 | #define SCODE_TYPES (SCODE | MTS) | ||
97 | |||
98 | |||
99 | /* Newer types not defined on videodev2.h. | ||
100 | The original idea were to move all those types to videodev2.h, but | ||
101 | it seemed overkill, since, with the exception of SECAM/K3, the other | ||
102 | types seem to be autodetected. | ||
103 | It is not clear where secam/k3 is used, nor we have a feedback of this | ||
104 | working or being autodetected by the standard secam firmware. | ||
105 | */ | ||
106 | |||
107 | #define V4L2_STD_SECAM_K3 (0x04000000) | ||
108 | |||
109 | /* Audio types */ | ||
110 | |||
111 | #define V4L2_STD_A2_A (1LL<<32) | ||
112 | #define V4L2_STD_A2_B (1LL<<33) | ||
113 | #define V4L2_STD_NICAM_A (1LL<<34) | ||
114 | #define V4L2_STD_NICAM_B (1LL<<35) | ||
115 | #define V4L2_STD_AM (1LL<<36) | ||
116 | #define V4L2_STD_BTSC (1LL<<37) | ||
117 | #define V4L2_STD_EIAJ (1LL<<38) | ||
118 | |||
119 | #define V4L2_STD_A2 (V4L2_STD_A2_A | V4L2_STD_A2_B) | ||
120 | #define V4L2_STD_NICAM (V4L2_STD_NICAM_A | V4L2_STD_NICAM_B) | ||
121 | |||
122 | /* To preserve backward compatibilty, | ||
123 | (std & V4L2_STD_AUDIO) = 0 means that ALL audio stds are supported | ||
124 | */ | ||
125 | |||
126 | #define V4L2_STD_AUDIO (V4L2_STD_A2 | \ | ||
127 | V4L2_STD_NICAM | \ | ||
128 | V4L2_STD_AM | \ | ||
129 | V4L2_STD_BTSC | \ | ||
130 | V4L2_STD_EIAJ) | ||
131 | |||
132 | /* Used standards with audio restrictions */ | ||
133 | |||
134 | #define V4L2_STD_PAL_BG_A2_A (V4L2_STD_PAL_BG | V4L2_STD_A2_A) | ||
135 | #define V4L2_STD_PAL_BG_A2_B (V4L2_STD_PAL_BG | V4L2_STD_A2_B) | ||
136 | #define V4L2_STD_PAL_BG_NICAM_A (V4L2_STD_PAL_BG | V4L2_STD_NICAM_A) | ||
137 | #define V4L2_STD_PAL_BG_NICAM_B (V4L2_STD_PAL_BG | V4L2_STD_NICAM_B) | ||
138 | #define V4L2_STD_PAL_DK_A2 (V4L2_STD_PAL_DK | V4L2_STD_A2) | ||
139 | #define V4L2_STD_PAL_DK_NICAM (V4L2_STD_PAL_DK | V4L2_STD_NICAM) | ||
140 | #define V4L2_STD_SECAM_L_NICAM (V4L2_STD_SECAM_L | V4L2_STD_NICAM) | ||
141 | #define V4L2_STD_SECAM_L_AM (V4L2_STD_SECAM_L | V4L2_STD_AM) | ||
diff --git a/drivers/media/tuners/tuner-xc2028.c b/drivers/media/tuners/tuner-xc2028.c new file mode 100644 index 000000000000..7bcb6b0ff1df --- /dev/null +++ b/drivers/media/tuners/tuner-xc2028.c | |||
@@ -0,0 +1,1509 @@ | |||
1 | /* tuner-xc2028 | ||
2 | * | ||
3 | * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org) | ||
4 | * | ||
5 | * Copyright (c) 2007 Michel Ludwig (michel.ludwig@gmail.com) | ||
6 | * - frontend interface | ||
7 | * | ||
8 | * This code is placed under the terms of the GNU General Public License v2 | ||
9 | */ | ||
10 | |||
11 | #include <linux/i2c.h> | ||
12 | #include <asm/div64.h> | ||
13 | #include <linux/firmware.h> | ||
14 | #include <linux/videodev2.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <media/tuner.h> | ||
17 | #include <linux/mutex.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <asm/unaligned.h> | ||
20 | #include "tuner-i2c.h" | ||
21 | #include "tuner-xc2028.h" | ||
22 | #include "tuner-xc2028-types.h" | ||
23 | |||
24 | #include <linux/dvb/frontend.h> | ||
25 | #include "dvb_frontend.h" | ||
26 | |||
27 | /* Registers (Write-only) */ | ||
28 | #define XREG_INIT 0x00 | ||
29 | #define XREG_RF_FREQ 0x02 | ||
30 | #define XREG_POWER_DOWN 0x08 | ||
31 | |||
32 | /* Registers (Read-only) */ | ||
33 | #define XREG_FREQ_ERROR 0x01 | ||
34 | #define XREG_LOCK 0x02 | ||
35 | #define XREG_VERSION 0x04 | ||
36 | #define XREG_PRODUCT_ID 0x08 | ||
37 | #define XREG_HSYNC_FREQ 0x10 | ||
38 | #define XREG_FRAME_LINES 0x20 | ||
39 | #define XREG_SNR 0x40 | ||
40 | |||
41 | #define XREG_ADC_ENV 0x0100 | ||
42 | |||
43 | static int debug; | ||
44 | module_param(debug, int, 0644); | ||
45 | MODULE_PARM_DESC(debug, "enable verbose debug messages"); | ||
46 | |||
47 | static int no_poweroff; | ||
48 | module_param(no_poweroff, int, 0644); | ||
49 | MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n" | ||
50 | "1 keep device energized and with tuner ready all the times.\n" | ||
51 | " Faster, but consumes more power and keeps the device hotter\n"); | ||
52 | |||
53 | static char audio_std[8]; | ||
54 | module_param_string(audio_std, audio_std, sizeof(audio_std), 0); | ||
55 | MODULE_PARM_DESC(audio_std, | ||
56 | "Audio standard. XC3028 audio decoder explicitly " | ||
57 | "needs to know what audio\n" | ||
58 | "standard is needed for some video standards with audio A2 or NICAM.\n" | ||
59 | "The valid values are:\n" | ||
60 | "A2\n" | ||
61 | "A2/A\n" | ||
62 | "A2/B\n" | ||
63 | "NICAM\n" | ||
64 | "NICAM/A\n" | ||
65 | "NICAM/B\n"); | ||
66 | |||
67 | static char firmware_name[30]; | ||
68 | module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0); | ||
69 | MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the " | ||
70 | "default firmware name\n"); | ||
71 | |||
72 | static LIST_HEAD(hybrid_tuner_instance_list); | ||
73 | static DEFINE_MUTEX(xc2028_list_mutex); | ||
74 | |||
75 | /* struct for storing firmware table */ | ||
76 | struct firmware_description { | ||
77 | unsigned int type; | ||
78 | v4l2_std_id id; | ||
79 | __u16 int_freq; | ||
80 | unsigned char *ptr; | ||
81 | unsigned int size; | ||
82 | }; | ||
83 | |||
84 | struct firmware_properties { | ||
85 | unsigned int type; | ||
86 | v4l2_std_id id; | ||
87 | v4l2_std_id std_req; | ||
88 | __u16 int_freq; | ||
89 | unsigned int scode_table; | ||
90 | int scode_nr; | ||
91 | }; | ||
92 | |||
93 | enum xc2028_state { | ||
94 | XC2028_NO_FIRMWARE = 0, | ||
95 | XC2028_WAITING_FIRMWARE, | ||
96 | XC2028_ACTIVE, | ||
97 | XC2028_SLEEP, | ||
98 | XC2028_NODEV, | ||
99 | }; | ||
100 | |||
101 | struct xc2028_data { | ||
102 | struct list_head hybrid_tuner_instance_list; | ||
103 | struct tuner_i2c_props i2c_props; | ||
104 | __u32 frequency; | ||
105 | |||
106 | enum xc2028_state state; | ||
107 | const char *fname; | ||
108 | |||
109 | struct firmware_description *firm; | ||
110 | int firm_size; | ||
111 | __u16 firm_version; | ||
112 | |||
113 | __u16 hwmodel; | ||
114 | __u16 hwvers; | ||
115 | |||
116 | struct xc2028_ctrl ctrl; | ||
117 | |||
118 | struct firmware_properties cur_fw; | ||
119 | |||
120 | struct mutex lock; | ||
121 | }; | ||
122 | |||
123 | #define i2c_send(priv, buf, size) ({ \ | ||
124 | int _rc; \ | ||
125 | _rc = tuner_i2c_xfer_send(&priv->i2c_props, buf, size); \ | ||
126 | if (size != _rc) \ | ||
127 | tuner_info("i2c output error: rc = %d (should be %d)\n",\ | ||
128 | _rc, (int)size); \ | ||
129 | if (priv->ctrl.msleep) \ | ||
130 | msleep(priv->ctrl.msleep); \ | ||
131 | _rc; \ | ||
132 | }) | ||
133 | |||
134 | #define i2c_rcv(priv, buf, size) ({ \ | ||
135 | int _rc; \ | ||
136 | _rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, size); \ | ||
137 | if (size != _rc) \ | ||
138 | tuner_err("i2c input error: rc = %d (should be %d)\n", \ | ||
139 | _rc, (int)size); \ | ||
140 | _rc; \ | ||
141 | }) | ||
142 | |||
143 | #define i2c_send_recv(priv, obuf, osize, ibuf, isize) ({ \ | ||
144 | int _rc; \ | ||
145 | _rc = tuner_i2c_xfer_send_recv(&priv->i2c_props, obuf, osize, \ | ||
146 | ibuf, isize); \ | ||
147 | if (isize != _rc) \ | ||
148 | tuner_err("i2c input error: rc = %d (should be %d)\n", \ | ||
149 | _rc, (int)isize); \ | ||
150 | if (priv->ctrl.msleep) \ | ||
151 | msleep(priv->ctrl.msleep); \ | ||
152 | _rc; \ | ||
153 | }) | ||
154 | |||
155 | #define send_seq(priv, data...) ({ \ | ||
156 | static u8 _val[] = data; \ | ||
157 | int _rc; \ | ||
158 | if (sizeof(_val) != \ | ||
159 | (_rc = tuner_i2c_xfer_send(&priv->i2c_props, \ | ||
160 | _val, sizeof(_val)))) { \ | ||
161 | tuner_err("Error on line %d: %d\n", __LINE__, _rc); \ | ||
162 | } else if (priv->ctrl.msleep) \ | ||
163 | msleep(priv->ctrl.msleep); \ | ||
164 | _rc; \ | ||
165 | }) | ||
166 | |||
167 | static int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val) | ||
168 | { | ||
169 | unsigned char buf[2]; | ||
170 | unsigned char ibuf[2]; | ||
171 | |||
172 | tuner_dbg("%s %04x called\n", __func__, reg); | ||
173 | |||
174 | buf[0] = reg >> 8; | ||
175 | buf[1] = (unsigned char) reg; | ||
176 | |||
177 | if (i2c_send_recv(priv, buf, 2, ibuf, 2) != 2) | ||
178 | return -EIO; | ||
179 | |||
180 | *val = (ibuf[1]) | (ibuf[0] << 8); | ||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | #define dump_firm_type(t) dump_firm_type_and_int_freq(t, 0) | ||
185 | static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq) | ||
186 | { | ||
187 | if (type & BASE) | ||
188 | printk("BASE "); | ||
189 | if (type & INIT1) | ||
190 | printk("INIT1 "); | ||
191 | if (type & F8MHZ) | ||
192 | printk("F8MHZ "); | ||
193 | if (type & MTS) | ||
194 | printk("MTS "); | ||
195 | if (type & D2620) | ||
196 | printk("D2620 "); | ||
197 | if (type & D2633) | ||
198 | printk("D2633 "); | ||
199 | if (type & DTV6) | ||
200 | printk("DTV6 "); | ||
201 | if (type & QAM) | ||
202 | printk("QAM "); | ||
203 | if (type & DTV7) | ||
204 | printk("DTV7 "); | ||
205 | if (type & DTV78) | ||
206 | printk("DTV78 "); | ||
207 | if (type & DTV8) | ||
208 | printk("DTV8 "); | ||
209 | if (type & FM) | ||
210 | printk("FM "); | ||
211 | if (type & INPUT1) | ||
212 | printk("INPUT1 "); | ||
213 | if (type & LCD) | ||
214 | printk("LCD "); | ||
215 | if (type & NOGD) | ||
216 | printk("NOGD "); | ||
217 | if (type & MONO) | ||
218 | printk("MONO "); | ||
219 | if (type & ATSC) | ||
220 | printk("ATSC "); | ||
221 | if (type & IF) | ||
222 | printk("IF "); | ||
223 | if (type & LG60) | ||
224 | printk("LG60 "); | ||
225 | if (type & ATI638) | ||
226 | printk("ATI638 "); | ||
227 | if (type & OREN538) | ||
228 | printk("OREN538 "); | ||
229 | if (type & OREN36) | ||
230 | printk("OREN36 "); | ||
231 | if (type & TOYOTA388) | ||
232 | printk("TOYOTA388 "); | ||
233 | if (type & TOYOTA794) | ||
234 | printk("TOYOTA794 "); | ||
235 | if (type & DIBCOM52) | ||
236 | printk("DIBCOM52 "); | ||
237 | if (type & ZARLINK456) | ||
238 | printk("ZARLINK456 "); | ||
239 | if (type & CHINA) | ||
240 | printk("CHINA "); | ||
241 | if (type & F6MHZ) | ||
242 | printk("F6MHZ "); | ||
243 | if (type & INPUT2) | ||
244 | printk("INPUT2 "); | ||
245 | if (type & SCODE) | ||
246 | printk("SCODE "); | ||
247 | if (type & HAS_IF) | ||
248 | printk("HAS_IF_%d ", int_freq); | ||
249 | } | ||
250 | |||
251 | static v4l2_std_id parse_audio_std_option(void) | ||
252 | { | ||
253 | if (strcasecmp(audio_std, "A2") == 0) | ||
254 | return V4L2_STD_A2; | ||
255 | if (strcasecmp(audio_std, "A2/A") == 0) | ||
256 | return V4L2_STD_A2_A; | ||
257 | if (strcasecmp(audio_std, "A2/B") == 0) | ||
258 | return V4L2_STD_A2_B; | ||
259 | if (strcasecmp(audio_std, "NICAM") == 0) | ||
260 | return V4L2_STD_NICAM; | ||
261 | if (strcasecmp(audio_std, "NICAM/A") == 0) | ||
262 | return V4L2_STD_NICAM_A; | ||
263 | if (strcasecmp(audio_std, "NICAM/B") == 0) | ||
264 | return V4L2_STD_NICAM_B; | ||
265 | |||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | static int check_device_status(struct xc2028_data *priv) | ||
270 | { | ||
271 | switch (priv->state) { | ||
272 | case XC2028_NO_FIRMWARE: | ||
273 | case XC2028_WAITING_FIRMWARE: | ||
274 | return -EAGAIN; | ||
275 | case XC2028_ACTIVE: | ||
276 | case XC2028_SLEEP: | ||
277 | return 0; | ||
278 | case XC2028_NODEV: | ||
279 | return -ENODEV; | ||
280 | } | ||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | static void free_firmware(struct xc2028_data *priv) | ||
285 | { | ||
286 | int i; | ||
287 | tuner_dbg("%s called\n", __func__); | ||
288 | |||
289 | if (!priv->firm) | ||
290 | return; | ||
291 | |||
292 | for (i = 0; i < priv->firm_size; i++) | ||
293 | kfree(priv->firm[i].ptr); | ||
294 | |||
295 | kfree(priv->firm); | ||
296 | |||
297 | priv->firm = NULL; | ||
298 | priv->firm_size = 0; | ||
299 | priv->state = XC2028_NO_FIRMWARE; | ||
300 | |||
301 | memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); | ||
302 | } | ||
303 | |||
304 | static int load_all_firmwares(struct dvb_frontend *fe, | ||
305 | const struct firmware *fw) | ||
306 | { | ||
307 | struct xc2028_data *priv = fe->tuner_priv; | ||
308 | const unsigned char *p, *endp; | ||
309 | int rc = 0; | ||
310 | int n, n_array; | ||
311 | char name[33]; | ||
312 | |||
313 | tuner_dbg("%s called\n", __func__); | ||
314 | |||
315 | p = fw->data; | ||
316 | endp = p + fw->size; | ||
317 | |||
318 | if (fw->size < sizeof(name) - 1 + 2 + 2) { | ||
319 | tuner_err("Error: firmware file %s has invalid size!\n", | ||
320 | priv->fname); | ||
321 | goto corrupt; | ||
322 | } | ||
323 | |||
324 | memcpy(name, p, sizeof(name) - 1); | ||
325 | name[sizeof(name) - 1] = 0; | ||
326 | p += sizeof(name) - 1; | ||
327 | |||
328 | priv->firm_version = get_unaligned_le16(p); | ||
329 | p += 2; | ||
330 | |||
331 | n_array = get_unaligned_le16(p); | ||
332 | p += 2; | ||
333 | |||
334 | tuner_info("Loading %d firmware images from %s, type: %s, ver %d.%d\n", | ||
335 | n_array, priv->fname, name, | ||
336 | priv->firm_version >> 8, priv->firm_version & 0xff); | ||
337 | |||
338 | priv->firm = kcalloc(n_array, sizeof(*priv->firm), GFP_KERNEL); | ||
339 | if (priv->firm == NULL) { | ||
340 | tuner_err("Not enough memory to load firmware file.\n"); | ||
341 | rc = -ENOMEM; | ||
342 | goto err; | ||
343 | } | ||
344 | priv->firm_size = n_array; | ||
345 | |||
346 | n = -1; | ||
347 | while (p < endp) { | ||
348 | __u32 type, size; | ||
349 | v4l2_std_id id; | ||
350 | __u16 int_freq = 0; | ||
351 | |||
352 | n++; | ||
353 | if (n >= n_array) { | ||
354 | tuner_err("More firmware images in file than " | ||
355 | "were expected!\n"); | ||
356 | goto corrupt; | ||
357 | } | ||
358 | |||
359 | /* Checks if there's enough bytes to read */ | ||
360 | if (endp - p < sizeof(type) + sizeof(id) + sizeof(size)) | ||
361 | goto header; | ||
362 | |||
363 | type = get_unaligned_le32(p); | ||
364 | p += sizeof(type); | ||
365 | |||
366 | id = get_unaligned_le64(p); | ||
367 | p += sizeof(id); | ||
368 | |||
369 | if (type & HAS_IF) { | ||
370 | int_freq = get_unaligned_le16(p); | ||
371 | p += sizeof(int_freq); | ||
372 | if (endp - p < sizeof(size)) | ||
373 | goto header; | ||
374 | } | ||
375 | |||
376 | size = get_unaligned_le32(p); | ||
377 | p += sizeof(size); | ||
378 | |||
379 | if (!size || size > endp - p) { | ||
380 | tuner_err("Firmware type "); | ||
381 | dump_firm_type(type); | ||
382 | printk("(%x), id %llx is corrupted " | ||
383 | "(size=%d, expected %d)\n", | ||
384 | type, (unsigned long long)id, | ||
385 | (unsigned)(endp - p), size); | ||
386 | goto corrupt; | ||
387 | } | ||
388 | |||
389 | priv->firm[n].ptr = kzalloc(size, GFP_KERNEL); | ||
390 | if (priv->firm[n].ptr == NULL) { | ||
391 | tuner_err("Not enough memory to load firmware file.\n"); | ||
392 | rc = -ENOMEM; | ||
393 | goto err; | ||
394 | } | ||
395 | tuner_dbg("Reading firmware type "); | ||
396 | if (debug) { | ||
397 | dump_firm_type_and_int_freq(type, int_freq); | ||
398 | printk("(%x), id %llx, size=%d.\n", | ||
399 | type, (unsigned long long)id, size); | ||
400 | } | ||
401 | |||
402 | memcpy(priv->firm[n].ptr, p, size); | ||
403 | priv->firm[n].type = type; | ||
404 | priv->firm[n].id = id; | ||
405 | priv->firm[n].size = size; | ||
406 | priv->firm[n].int_freq = int_freq; | ||
407 | |||
408 | p += size; | ||
409 | } | ||
410 | |||
411 | if (n + 1 != priv->firm_size) { | ||
412 | tuner_err("Firmware file is incomplete!\n"); | ||
413 | goto corrupt; | ||
414 | } | ||
415 | |||
416 | goto done; | ||
417 | |||
418 | header: | ||
419 | tuner_err("Firmware header is incomplete!\n"); | ||
420 | corrupt: | ||
421 | rc = -EINVAL; | ||
422 | tuner_err("Error: firmware file is corrupted!\n"); | ||
423 | |||
424 | err: | ||
425 | tuner_info("Releasing partially loaded firmware file.\n"); | ||
426 | free_firmware(priv); | ||
427 | |||
428 | done: | ||
429 | if (rc == 0) | ||
430 | tuner_dbg("Firmware files loaded.\n"); | ||
431 | else | ||
432 | priv->state = XC2028_NODEV; | ||
433 | |||
434 | return rc; | ||
435 | } | ||
436 | |||
437 | static int seek_firmware(struct dvb_frontend *fe, unsigned int type, | ||
438 | v4l2_std_id *id) | ||
439 | { | ||
440 | struct xc2028_data *priv = fe->tuner_priv; | ||
441 | int i, best_i = -1, best_nr_matches = 0; | ||
442 | unsigned int type_mask = 0; | ||
443 | |||
444 | tuner_dbg("%s called, want type=", __func__); | ||
445 | if (debug) { | ||
446 | dump_firm_type(type); | ||
447 | printk("(%x), id %016llx.\n", type, (unsigned long long)*id); | ||
448 | } | ||
449 | |||
450 | if (!priv->firm) { | ||
451 | tuner_err("Error! firmware not loaded\n"); | ||
452 | return -EINVAL; | ||
453 | } | ||
454 | |||
455 | if (((type & ~SCODE) == 0) && (*id == 0)) | ||
456 | *id = V4L2_STD_PAL; | ||
457 | |||
458 | if (type & BASE) | ||
459 | type_mask = BASE_TYPES; | ||
460 | else if (type & SCODE) { | ||
461 | type &= SCODE_TYPES; | ||
462 | type_mask = SCODE_TYPES & ~HAS_IF; | ||
463 | } else if (type & DTV_TYPES) | ||
464 | type_mask = DTV_TYPES; | ||
465 | else if (type & STD_SPECIFIC_TYPES) | ||
466 | type_mask = STD_SPECIFIC_TYPES; | ||
467 | |||
468 | type &= type_mask; | ||
469 | |||
470 | if (!(type & SCODE)) | ||
471 | type_mask = ~0; | ||
472 | |||
473 | /* Seek for exact match */ | ||
474 | for (i = 0; i < priv->firm_size; i++) { | ||
475 | if ((type == (priv->firm[i].type & type_mask)) && | ||
476 | (*id == priv->firm[i].id)) | ||
477 | goto found; | ||
478 | } | ||
479 | |||
480 | /* Seek for generic video standard match */ | ||
481 | for (i = 0; i < priv->firm_size; i++) { | ||
482 | v4l2_std_id match_mask; | ||
483 | int nr_matches; | ||
484 | |||
485 | if (type != (priv->firm[i].type & type_mask)) | ||
486 | continue; | ||
487 | |||
488 | match_mask = *id & priv->firm[i].id; | ||
489 | if (!match_mask) | ||
490 | continue; | ||
491 | |||
492 | if ((*id & match_mask) == *id) | ||
493 | goto found; /* Supports all the requested standards */ | ||
494 | |||
495 | nr_matches = hweight64(match_mask); | ||
496 | if (nr_matches > best_nr_matches) { | ||
497 | best_nr_matches = nr_matches; | ||
498 | best_i = i; | ||
499 | } | ||
500 | } | ||
501 | |||
502 | if (best_nr_matches > 0) { | ||
503 | tuner_dbg("Selecting best matching firmware (%d bits) for " | ||
504 | "type=", best_nr_matches); | ||
505 | dump_firm_type(type); | ||
506 | printk("(%x), id %016llx:\n", type, (unsigned long long)*id); | ||
507 | i = best_i; | ||
508 | goto found; | ||
509 | } | ||
510 | |||
511 | /*FIXME: Would make sense to seek for type "hint" match ? */ | ||
512 | |||
513 | i = -ENOENT; | ||
514 | goto ret; | ||
515 | |||
516 | found: | ||
517 | *id = priv->firm[i].id; | ||
518 | |||
519 | ret: | ||
520 | tuner_dbg("%s firmware for type=", (i < 0) ? "Can't find" : "Found"); | ||
521 | if (debug) { | ||
522 | dump_firm_type(type); | ||
523 | printk("(%x), id %016llx.\n", type, (unsigned long long)*id); | ||
524 | } | ||
525 | return i; | ||
526 | } | ||
527 | |||
528 | static inline int do_tuner_callback(struct dvb_frontend *fe, int cmd, int arg) | ||
529 | { | ||
530 | struct xc2028_data *priv = fe->tuner_priv; | ||
531 | |||
532 | /* analog side (tuner-core) uses i2c_adap->algo_data. | ||
533 | * digital side is not guaranteed to have algo_data defined. | ||
534 | * | ||
535 | * digital side will always have fe->dvb defined. | ||
536 | * analog side (tuner-core) doesn't (yet) define fe->dvb. | ||
537 | */ | ||
538 | |||
539 | return (!fe->callback) ? -EINVAL : | ||
540 | fe->callback(((fe->dvb) && (fe->dvb->priv)) ? | ||
541 | fe->dvb->priv : priv->i2c_props.adap->algo_data, | ||
542 | DVB_FRONTEND_COMPONENT_TUNER, cmd, arg); | ||
543 | } | ||
544 | |||
545 | static int load_firmware(struct dvb_frontend *fe, unsigned int type, | ||
546 | v4l2_std_id *id) | ||
547 | { | ||
548 | struct xc2028_data *priv = fe->tuner_priv; | ||
549 | int pos, rc; | ||
550 | unsigned char *p, *endp, buf[priv->ctrl.max_len]; | ||
551 | |||
552 | tuner_dbg("%s called\n", __func__); | ||
553 | |||
554 | pos = seek_firmware(fe, type, id); | ||
555 | if (pos < 0) | ||
556 | return pos; | ||
557 | |||
558 | tuner_info("Loading firmware for type="); | ||
559 | dump_firm_type(priv->firm[pos].type); | ||
560 | printk("(%x), id %016llx.\n", priv->firm[pos].type, | ||
561 | (unsigned long long)*id); | ||
562 | |||
563 | p = priv->firm[pos].ptr; | ||
564 | endp = p + priv->firm[pos].size; | ||
565 | |||
566 | while (p < endp) { | ||
567 | __u16 size; | ||
568 | |||
569 | /* Checks if there's enough bytes to read */ | ||
570 | if (p + sizeof(size) > endp) { | ||
571 | tuner_err("Firmware chunk size is wrong\n"); | ||
572 | return -EINVAL; | ||
573 | } | ||
574 | |||
575 | size = le16_to_cpu(*(__u16 *) p); | ||
576 | p += sizeof(size); | ||
577 | |||
578 | if (size == 0xffff) | ||
579 | return 0; | ||
580 | |||
581 | if (!size) { | ||
582 | /* Special callback command received */ | ||
583 | rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0); | ||
584 | if (rc < 0) { | ||
585 | tuner_err("Error at RESET code %d\n", | ||
586 | (*p) & 0x7f); | ||
587 | return -EINVAL; | ||
588 | } | ||
589 | continue; | ||
590 | } | ||
591 | if (size >= 0xff00) { | ||
592 | switch (size) { | ||
593 | case 0xff00: | ||
594 | rc = do_tuner_callback(fe, XC2028_RESET_CLK, 0); | ||
595 | if (rc < 0) { | ||
596 | tuner_err("Error at RESET code %d\n", | ||
597 | (*p) & 0x7f); | ||
598 | return -EINVAL; | ||
599 | } | ||
600 | break; | ||
601 | default: | ||
602 | tuner_info("Invalid RESET code %d\n", | ||
603 | size & 0x7f); | ||
604 | return -EINVAL; | ||
605 | |||
606 | } | ||
607 | continue; | ||
608 | } | ||
609 | |||
610 | /* Checks for a sleep command */ | ||
611 | if (size & 0x8000) { | ||
612 | msleep(size & 0x7fff); | ||
613 | continue; | ||
614 | } | ||
615 | |||
616 | if ((size + p > endp)) { | ||
617 | tuner_err("missing bytes: need %d, have %d\n", | ||
618 | size, (int)(endp - p)); | ||
619 | return -EINVAL; | ||
620 | } | ||
621 | |||
622 | buf[0] = *p; | ||
623 | p++; | ||
624 | size--; | ||
625 | |||
626 | /* Sends message chunks */ | ||
627 | while (size > 0) { | ||
628 | int len = (size < priv->ctrl.max_len - 1) ? | ||
629 | size : priv->ctrl.max_len - 1; | ||
630 | |||
631 | memcpy(buf + 1, p, len); | ||
632 | |||
633 | rc = i2c_send(priv, buf, len + 1); | ||
634 | if (rc < 0) { | ||
635 | tuner_err("%d returned from send\n", rc); | ||
636 | return -EINVAL; | ||
637 | } | ||
638 | |||
639 | p += len; | ||
640 | size -= len; | ||
641 | } | ||
642 | |||
643 | /* silently fail if the frontend doesn't support I2C flush */ | ||
644 | rc = do_tuner_callback(fe, XC2028_I2C_FLUSH, 0); | ||
645 | if ((rc < 0) && (rc != -EINVAL)) { | ||
646 | tuner_err("error executing flush: %d\n", rc); | ||
647 | return rc; | ||
648 | } | ||
649 | } | ||
650 | return 0; | ||
651 | } | ||
652 | |||
653 | static int load_scode(struct dvb_frontend *fe, unsigned int type, | ||
654 | v4l2_std_id *id, __u16 int_freq, int scode) | ||
655 | { | ||
656 | struct xc2028_data *priv = fe->tuner_priv; | ||
657 | int pos, rc; | ||
658 | unsigned char *p; | ||
659 | |||
660 | tuner_dbg("%s called\n", __func__); | ||
661 | |||
662 | if (!int_freq) { | ||
663 | pos = seek_firmware(fe, type, id); | ||
664 | if (pos < 0) | ||
665 | return pos; | ||
666 | } else { | ||
667 | for (pos = 0; pos < priv->firm_size; pos++) { | ||
668 | if ((priv->firm[pos].int_freq == int_freq) && | ||
669 | (priv->firm[pos].type & HAS_IF)) | ||
670 | break; | ||
671 | } | ||
672 | if (pos == priv->firm_size) | ||
673 | return -ENOENT; | ||
674 | } | ||
675 | |||
676 | p = priv->firm[pos].ptr; | ||
677 | |||
678 | if (priv->firm[pos].type & HAS_IF) { | ||
679 | if (priv->firm[pos].size != 12 * 16 || scode >= 16) | ||
680 | return -EINVAL; | ||
681 | p += 12 * scode; | ||
682 | } else { | ||
683 | /* 16 SCODE entries per file; each SCODE entry is 12 bytes and | ||
684 | * has a 2-byte size header in the firmware format. */ | ||
685 | if (priv->firm[pos].size != 14 * 16 || scode >= 16 || | ||
686 | le16_to_cpu(*(__u16 *)(p + 14 * scode)) != 12) | ||
687 | return -EINVAL; | ||
688 | p += 14 * scode + 2; | ||
689 | } | ||
690 | |||
691 | tuner_info("Loading SCODE for type="); | ||
692 | dump_firm_type_and_int_freq(priv->firm[pos].type, | ||
693 | priv->firm[pos].int_freq); | ||
694 | printk("(%x), id %016llx.\n", priv->firm[pos].type, | ||
695 | (unsigned long long)*id); | ||
696 | |||
697 | if (priv->firm_version < 0x0202) | ||
698 | rc = send_seq(priv, {0x20, 0x00, 0x00, 0x00}); | ||
699 | else | ||
700 | rc = send_seq(priv, {0xa0, 0x00, 0x00, 0x00}); | ||
701 | if (rc < 0) | ||
702 | return -EIO; | ||
703 | |||
704 | rc = i2c_send(priv, p, 12); | ||
705 | if (rc < 0) | ||
706 | return -EIO; | ||
707 | |||
708 | rc = send_seq(priv, {0x00, 0x8c}); | ||
709 | if (rc < 0) | ||
710 | return -EIO; | ||
711 | |||
712 | return 0; | ||
713 | } | ||
714 | |||
715 | static int check_firmware(struct dvb_frontend *fe, unsigned int type, | ||
716 | v4l2_std_id std, __u16 int_freq) | ||
717 | { | ||
718 | struct xc2028_data *priv = fe->tuner_priv; | ||
719 | struct firmware_properties new_fw; | ||
720 | int rc, retry_count = 0; | ||
721 | u16 version, hwmodel; | ||
722 | v4l2_std_id std0; | ||
723 | |||
724 | tuner_dbg("%s called\n", __func__); | ||
725 | |||
726 | rc = check_device_status(priv); | ||
727 | if (rc < 0) | ||
728 | return rc; | ||
729 | |||
730 | if (priv->ctrl.mts && !(type & FM)) | ||
731 | type |= MTS; | ||
732 | |||
733 | retry: | ||
734 | new_fw.type = type; | ||
735 | new_fw.id = std; | ||
736 | new_fw.std_req = std; | ||
737 | new_fw.scode_table = SCODE | priv->ctrl.scode_table; | ||
738 | new_fw.scode_nr = 0; | ||
739 | new_fw.int_freq = int_freq; | ||
740 | |||
741 | tuner_dbg("checking firmware, user requested type="); | ||
742 | if (debug) { | ||
743 | dump_firm_type(new_fw.type); | ||
744 | printk("(%x), id %016llx, ", new_fw.type, | ||
745 | (unsigned long long)new_fw.std_req); | ||
746 | if (!int_freq) { | ||
747 | printk("scode_tbl "); | ||
748 | dump_firm_type(priv->ctrl.scode_table); | ||
749 | printk("(%x), ", priv->ctrl.scode_table); | ||
750 | } else | ||
751 | printk("int_freq %d, ", new_fw.int_freq); | ||
752 | printk("scode_nr %d\n", new_fw.scode_nr); | ||
753 | } | ||
754 | |||
755 | /* | ||
756 | * No need to reload base firmware if it matches and if the tuner | ||
757 | * is not at sleep mode | ||
758 | */ | ||
759 | if ((priv->state == XC2028_ACTIVE) && | ||
760 | (((BASE | new_fw.type) & BASE_TYPES) == | ||
761 | (priv->cur_fw.type & BASE_TYPES))) { | ||
762 | tuner_dbg("BASE firmware not changed.\n"); | ||
763 | goto skip_base; | ||
764 | } | ||
765 | |||
766 | /* Updating BASE - forget about all currently loaded firmware */ | ||
767 | memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); | ||
768 | |||
769 | /* Reset is needed before loading firmware */ | ||
770 | rc = do_tuner_callback(fe, XC2028_TUNER_RESET, 0); | ||
771 | if (rc < 0) | ||
772 | goto fail; | ||
773 | |||
774 | /* BASE firmwares are all std0 */ | ||
775 | std0 = 0; | ||
776 | rc = load_firmware(fe, BASE | new_fw.type, &std0); | ||
777 | if (rc < 0) { | ||
778 | tuner_err("Error %d while loading base firmware\n", | ||
779 | rc); | ||
780 | goto fail; | ||
781 | } | ||
782 | |||
783 | /* Load INIT1, if needed */ | ||
784 | tuner_dbg("Load init1 firmware, if exists\n"); | ||
785 | |||
786 | rc = load_firmware(fe, BASE | INIT1 | new_fw.type, &std0); | ||
787 | if (rc == -ENOENT) | ||
788 | rc = load_firmware(fe, (BASE | INIT1 | new_fw.type) & ~F8MHZ, | ||
789 | &std0); | ||
790 | if (rc < 0 && rc != -ENOENT) { | ||
791 | tuner_err("Error %d while loading init1 firmware\n", | ||
792 | rc); | ||
793 | goto fail; | ||
794 | } | ||
795 | |||
796 | skip_base: | ||
797 | /* | ||
798 | * No need to reload standard specific firmware if base firmware | ||
799 | * was not reloaded and requested video standards have not changed. | ||
800 | */ | ||
801 | if (priv->cur_fw.type == (BASE | new_fw.type) && | ||
802 | priv->cur_fw.std_req == std) { | ||
803 | tuner_dbg("Std-specific firmware already loaded.\n"); | ||
804 | goto skip_std_specific; | ||
805 | } | ||
806 | |||
807 | /* Reloading std-specific firmware forces a SCODE update */ | ||
808 | priv->cur_fw.scode_table = 0; | ||
809 | |||
810 | rc = load_firmware(fe, new_fw.type, &new_fw.id); | ||
811 | if (rc == -ENOENT) | ||
812 | rc = load_firmware(fe, new_fw.type & ~F8MHZ, &new_fw.id); | ||
813 | |||
814 | if (rc < 0) | ||
815 | goto fail; | ||
816 | |||
817 | skip_std_specific: | ||
818 | if (priv->cur_fw.scode_table == new_fw.scode_table && | ||
819 | priv->cur_fw.scode_nr == new_fw.scode_nr) { | ||
820 | tuner_dbg("SCODE firmware already loaded.\n"); | ||
821 | goto check_device; | ||
822 | } | ||
823 | |||
824 | if (new_fw.type & FM) | ||
825 | goto check_device; | ||
826 | |||
827 | /* Load SCODE firmware, if exists */ | ||
828 | tuner_dbg("Trying to load scode %d\n", new_fw.scode_nr); | ||
829 | |||
830 | rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id, | ||
831 | new_fw.int_freq, new_fw.scode_nr); | ||
832 | |||
833 | check_device: | ||
834 | if (xc2028_get_reg(priv, 0x0004, &version) < 0 || | ||
835 | xc2028_get_reg(priv, 0x0008, &hwmodel) < 0) { | ||
836 | tuner_err("Unable to read tuner registers.\n"); | ||
837 | goto fail; | ||
838 | } | ||
839 | |||
840 | tuner_dbg("Device is Xceive %d version %d.%d, " | ||
841 | "firmware version %d.%d\n", | ||
842 | hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8, | ||
843 | (version & 0xf0) >> 4, version & 0xf); | ||
844 | |||
845 | |||
846 | if (priv->ctrl.read_not_reliable) | ||
847 | goto read_not_reliable; | ||
848 | |||
849 | /* Check firmware version against what we downloaded. */ | ||
850 | if (priv->firm_version != ((version & 0xf0) << 4 | (version & 0x0f))) { | ||
851 | if (!priv->ctrl.read_not_reliable) { | ||
852 | tuner_err("Incorrect readback of firmware version.\n"); | ||
853 | goto fail; | ||
854 | } else { | ||
855 | tuner_err("Returned an incorrect version. However, " | ||
856 | "read is not reliable enough. Ignoring it.\n"); | ||
857 | hwmodel = 3028; | ||
858 | } | ||
859 | } | ||
860 | |||
861 | /* Check that the tuner hardware model remains consistent over time. */ | ||
862 | if (priv->hwmodel == 0 && (hwmodel == 2028 || hwmodel == 3028)) { | ||
863 | priv->hwmodel = hwmodel; | ||
864 | priv->hwvers = version & 0xff00; | ||
865 | } else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel || | ||
866 | priv->hwvers != (version & 0xff00)) { | ||
867 | tuner_err("Read invalid device hardware information - tuner " | ||
868 | "hung?\n"); | ||
869 | goto fail; | ||
870 | } | ||
871 | |||
872 | read_not_reliable: | ||
873 | memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw)); | ||
874 | |||
875 | /* | ||
876 | * By setting BASE in cur_fw.type only after successfully loading all | ||
877 | * firmwares, we can: | ||
878 | * 1. Identify that BASE firmware with type=0 has been loaded; | ||
879 | * 2. Tell whether BASE firmware was just changed the next time through. | ||
880 | */ | ||
881 | priv->cur_fw.type |= BASE; | ||
882 | priv->state = XC2028_ACTIVE; | ||
883 | |||
884 | return 0; | ||
885 | |||
886 | fail: | ||
887 | priv->state = XC2028_SLEEP; | ||
888 | |||
889 | memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); | ||
890 | if (retry_count < 8) { | ||
891 | msleep(50); | ||
892 | retry_count++; | ||
893 | tuner_dbg("Retrying firmware load\n"); | ||
894 | goto retry; | ||
895 | } | ||
896 | |||
897 | if (rc == -ENOENT) | ||
898 | rc = -EINVAL; | ||
899 | return rc; | ||
900 | } | ||
901 | |||
902 | static int xc2028_signal(struct dvb_frontend *fe, u16 *strength) | ||
903 | { | ||
904 | struct xc2028_data *priv = fe->tuner_priv; | ||
905 | u16 frq_lock, signal = 0; | ||
906 | int rc, i; | ||
907 | |||
908 | tuner_dbg("%s called\n", __func__); | ||
909 | |||
910 | rc = check_device_status(priv); | ||
911 | if (rc < 0) | ||
912 | return rc; | ||
913 | |||
914 | mutex_lock(&priv->lock); | ||
915 | |||
916 | /* Sync Lock Indicator */ | ||
917 | for (i = 0; i < 3; i++) { | ||
918 | rc = xc2028_get_reg(priv, XREG_LOCK, &frq_lock); | ||
919 | if (rc < 0) | ||
920 | goto ret; | ||
921 | |||
922 | if (frq_lock) | ||
923 | break; | ||
924 | msleep(6); | ||
925 | } | ||
926 | |||
927 | /* Frequency didn't lock */ | ||
928 | if (frq_lock == 2) | ||
929 | goto ret; | ||
930 | |||
931 | /* Get SNR of the video signal */ | ||
932 | rc = xc2028_get_reg(priv, XREG_SNR, &signal); | ||
933 | if (rc < 0) | ||
934 | goto ret; | ||
935 | |||
936 | /* Signal level is 3 bits only */ | ||
937 | |||
938 | signal = ((1 << 12) - 1) | ((signal & 0x07) << 12); | ||
939 | |||
940 | ret: | ||
941 | mutex_unlock(&priv->lock); | ||
942 | |||
943 | *strength = signal; | ||
944 | |||
945 | tuner_dbg("signal strength is %d\n", signal); | ||
946 | |||
947 | return rc; | ||
948 | } | ||
949 | |||
950 | static int xc2028_get_afc(struct dvb_frontend *fe, s32 *afc) | ||
951 | { | ||
952 | struct xc2028_data *priv = fe->tuner_priv; | ||
953 | int i, rc; | ||
954 | u16 frq_lock = 0; | ||
955 | s16 afc_reg = 0; | ||
956 | |||
957 | rc = check_device_status(priv); | ||
958 | if (rc < 0) | ||
959 | return rc; | ||
960 | |||
961 | mutex_lock(&priv->lock); | ||
962 | |||
963 | /* Sync Lock Indicator */ | ||
964 | for (i = 0; i < 3; i++) { | ||
965 | rc = xc2028_get_reg(priv, XREG_LOCK, &frq_lock); | ||
966 | if (rc < 0) | ||
967 | goto ret; | ||
968 | |||
969 | if (frq_lock) | ||
970 | break; | ||
971 | msleep(6); | ||
972 | } | ||
973 | |||
974 | /* Frequency didn't lock */ | ||
975 | if (frq_lock == 2) | ||
976 | goto ret; | ||
977 | |||
978 | /* Get AFC */ | ||
979 | rc = xc2028_get_reg(priv, XREG_FREQ_ERROR, &afc_reg); | ||
980 | if (rc < 0) | ||
981 | goto ret; | ||
982 | |||
983 | *afc = afc_reg * 15625; /* Hz */ | ||
984 | |||
985 | tuner_dbg("AFC is %d Hz\n", *afc); | ||
986 | |||
987 | ret: | ||
988 | mutex_unlock(&priv->lock); | ||
989 | |||
990 | return rc; | ||
991 | } | ||
992 | |||
993 | #define DIV 15625 | ||
994 | |||
995 | static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */, | ||
996 | enum v4l2_tuner_type new_type, | ||
997 | unsigned int type, | ||
998 | v4l2_std_id std, | ||
999 | u16 int_freq) | ||
1000 | { | ||
1001 | struct xc2028_data *priv = fe->tuner_priv; | ||
1002 | int rc = -EINVAL; | ||
1003 | unsigned char buf[4]; | ||
1004 | u32 div, offset = 0; | ||
1005 | |||
1006 | tuner_dbg("%s called\n", __func__); | ||
1007 | |||
1008 | mutex_lock(&priv->lock); | ||
1009 | |||
1010 | tuner_dbg("should set frequency %d kHz\n", freq / 1000); | ||
1011 | |||
1012 | if (check_firmware(fe, type, std, int_freq) < 0) | ||
1013 | goto ret; | ||
1014 | |||
1015 | /* On some cases xc2028 can disable video output, if | ||
1016 | * very weak signals are received. By sending a soft | ||
1017 | * reset, this is re-enabled. So, it is better to always | ||
1018 | * send a soft reset before changing channels, to be sure | ||
1019 | * that xc2028 will be in a safe state. | ||
1020 | * Maybe this might also be needed for DTV. | ||
1021 | */ | ||
1022 | switch (new_type) { | ||
1023 | case V4L2_TUNER_ANALOG_TV: | ||
1024 | rc = send_seq(priv, {0x00, 0x00}); | ||
1025 | |||
1026 | /* Analog mode requires offset = 0 */ | ||
1027 | break; | ||
1028 | case V4L2_TUNER_RADIO: | ||
1029 | /* Radio mode requires offset = 0 */ | ||
1030 | break; | ||
1031 | case V4L2_TUNER_DIGITAL_TV: | ||
1032 | /* | ||
1033 | * Digital modes require an offset to adjust to the | ||
1034 | * proper frequency. The offset depends on what | ||
1035 | * firmware version is used. | ||
1036 | */ | ||
1037 | |||
1038 | /* | ||
1039 | * Adjust to the center frequency. This is calculated by the | ||
1040 | * formula: offset = 1.25MHz - BW/2 | ||
1041 | * For DTV 7/8, the firmware uses BW = 8000, so it needs a | ||
1042 | * further adjustment to get the frequency center on VHF | ||
1043 | */ | ||
1044 | |||
1045 | /* | ||
1046 | * The firmware DTV78 used to work fine in UHF band (8 MHz | ||
1047 | * bandwidth) but not at all in VHF band (7 MHz bandwidth). | ||
1048 | * The real problem was connected to the formula used to | ||
1049 | * calculate the center frequency offset in VHF band. | ||
1050 | * In fact, removing the 500KHz adjustment fixed the problem. | ||
1051 | * This is coherent to what was implemented for the DTV7 | ||
1052 | * firmware. | ||
1053 | * In the end, now the center frequency is the same for all 3 | ||
1054 | * firmwares (DTV7, DTV8, DTV78) and doesn't depend on channel | ||
1055 | * bandwidth. | ||
1056 | */ | ||
1057 | |||
1058 | if (priv->cur_fw.type & DTV6) | ||
1059 | offset = 1750000; | ||
1060 | else /* DTV7 or DTV8 or DTV78 */ | ||
1061 | offset = 2750000; | ||
1062 | |||
1063 | /* | ||
1064 | * xc3028 additional "magic" | ||
1065 | * Depending on the firmware version, it needs some adjustments | ||
1066 | * to properly centralize the frequency. This seems to be | ||
1067 | * needed to compensate the SCODE table adjustments made by | ||
1068 | * newer firmwares | ||
1069 | */ | ||
1070 | |||
1071 | /* | ||
1072 | * The proper adjustment would be to do it at s-code table. | ||
1073 | * However, this didn't work, as reported by | ||
1074 | * Robert Lowery <rglowery@exemail.com.au> | ||
1075 | */ | ||
1076 | |||
1077 | #if 0 | ||
1078 | /* | ||
1079 | * Still need tests for XC3028L (firmware 3.2 or upper) | ||
1080 | * So, for now, let's just comment the per-firmware | ||
1081 | * version of this change. Reports with xc3028l working | ||
1082 | * with and without the lines bellow are welcome | ||
1083 | */ | ||
1084 | |||
1085 | if (priv->firm_version < 0x0302) { | ||
1086 | if (priv->cur_fw.type & DTV7) | ||
1087 | offset += 500000; | ||
1088 | } else { | ||
1089 | if (priv->cur_fw.type & DTV7) | ||
1090 | offset -= 300000; | ||
1091 | else if (type != ATSC) /* DVB @6MHz, DTV 8 and DTV 7/8 */ | ||
1092 | offset += 200000; | ||
1093 | } | ||
1094 | #endif | ||
1095 | } | ||
1096 | |||
1097 | div = (freq - offset + DIV / 2) / DIV; | ||
1098 | |||
1099 | /* CMD= Set frequency */ | ||
1100 | if (priv->firm_version < 0x0202) | ||
1101 | rc = send_seq(priv, {0x00, XREG_RF_FREQ, 0x00, 0x00}); | ||
1102 | else | ||
1103 | rc = send_seq(priv, {0x80, XREG_RF_FREQ, 0x00, 0x00}); | ||
1104 | if (rc < 0) | ||
1105 | goto ret; | ||
1106 | |||
1107 | /* Return code shouldn't be checked. | ||
1108 | The reset CLK is needed only with tm6000. | ||
1109 | Driver should work fine even if this fails. | ||
1110 | */ | ||
1111 | if (priv->ctrl.msleep) | ||
1112 | msleep(priv->ctrl.msleep); | ||
1113 | do_tuner_callback(fe, XC2028_RESET_CLK, 1); | ||
1114 | |||
1115 | msleep(10); | ||
1116 | |||
1117 | buf[0] = 0xff & (div >> 24); | ||
1118 | buf[1] = 0xff & (div >> 16); | ||
1119 | buf[2] = 0xff & (div >> 8); | ||
1120 | buf[3] = 0xff & (div); | ||
1121 | |||
1122 | rc = i2c_send(priv, buf, sizeof(buf)); | ||
1123 | if (rc < 0) | ||
1124 | goto ret; | ||
1125 | msleep(100); | ||
1126 | |||
1127 | priv->frequency = freq; | ||
1128 | |||
1129 | tuner_dbg("divisor= %*ph (freq=%d.%03d)\n", 4, buf, | ||
1130 | freq / 1000000, (freq % 1000000) / 1000); | ||
1131 | |||
1132 | rc = 0; | ||
1133 | |||
1134 | ret: | ||
1135 | mutex_unlock(&priv->lock); | ||
1136 | |||
1137 | return rc; | ||
1138 | } | ||
1139 | |||
1140 | static int xc2028_set_analog_freq(struct dvb_frontend *fe, | ||
1141 | struct analog_parameters *p) | ||
1142 | { | ||
1143 | struct xc2028_data *priv = fe->tuner_priv; | ||
1144 | unsigned int type=0; | ||
1145 | |||
1146 | tuner_dbg("%s called\n", __func__); | ||
1147 | |||
1148 | if (p->mode == V4L2_TUNER_RADIO) { | ||
1149 | type |= FM; | ||
1150 | if (priv->ctrl.input1) | ||
1151 | type |= INPUT1; | ||
1152 | return generic_set_freq(fe, (625l * p->frequency) / 10, | ||
1153 | V4L2_TUNER_RADIO, type, 0, 0); | ||
1154 | } | ||
1155 | |||
1156 | /* if std is not defined, choose one */ | ||
1157 | if (!p->std) | ||
1158 | p->std = V4L2_STD_MN; | ||
1159 | |||
1160 | /* PAL/M, PAL/N, PAL/Nc and NTSC variants should use 6MHz firmware */ | ||
1161 | if (!(p->std & V4L2_STD_MN)) | ||
1162 | type |= F8MHZ; | ||
1163 | |||
1164 | /* Add audio hack to std mask */ | ||
1165 | p->std |= parse_audio_std_option(); | ||
1166 | |||
1167 | return generic_set_freq(fe, 62500l * p->frequency, | ||
1168 | V4L2_TUNER_ANALOG_TV, type, p->std, 0); | ||
1169 | } | ||
1170 | |||
1171 | static int xc2028_set_params(struct dvb_frontend *fe) | ||
1172 | { | ||
1173 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
1174 | u32 delsys = c->delivery_system; | ||
1175 | u32 bw = c->bandwidth_hz; | ||
1176 | struct xc2028_data *priv = fe->tuner_priv; | ||
1177 | int rc; | ||
1178 | unsigned int type = 0; | ||
1179 | u16 demod = 0; | ||
1180 | |||
1181 | tuner_dbg("%s called\n", __func__); | ||
1182 | |||
1183 | rc = check_device_status(priv); | ||
1184 | if (rc < 0) | ||
1185 | return rc; | ||
1186 | |||
1187 | switch (delsys) { | ||
1188 | case SYS_DVBT: | ||
1189 | case SYS_DVBT2: | ||
1190 | /* | ||
1191 | * The only countries with 6MHz seem to be Taiwan/Uruguay. | ||
1192 | * Both seem to require QAM firmware for OFDM decoding | ||
1193 | * Tested in Taiwan by Terry Wu <terrywu2009@gmail.com> | ||
1194 | */ | ||
1195 | if (bw <= 6000000) | ||
1196 | type |= QAM; | ||
1197 | |||
1198 | switch (priv->ctrl.type) { | ||
1199 | case XC2028_D2633: | ||
1200 | type |= D2633; | ||
1201 | break; | ||
1202 | case XC2028_D2620: | ||
1203 | type |= D2620; | ||
1204 | break; | ||
1205 | case XC2028_AUTO: | ||
1206 | default: | ||
1207 | /* Zarlink seems to need D2633 */ | ||
1208 | if (priv->ctrl.demod == XC3028_FE_ZARLINK456) | ||
1209 | type |= D2633; | ||
1210 | else | ||
1211 | type |= D2620; | ||
1212 | } | ||
1213 | break; | ||
1214 | case SYS_ATSC: | ||
1215 | /* The only ATSC firmware (at least on v2.7) is D2633 */ | ||
1216 | type |= ATSC | D2633; | ||
1217 | break; | ||
1218 | /* DVB-S and pure QAM (FE_QAM) are not supported */ | ||
1219 | default: | ||
1220 | return -EINVAL; | ||
1221 | } | ||
1222 | |||
1223 | if (bw <= 6000000) { | ||
1224 | type |= DTV6; | ||
1225 | priv->ctrl.vhfbw7 = 0; | ||
1226 | priv->ctrl.uhfbw8 = 0; | ||
1227 | } else if (bw <= 7000000) { | ||
1228 | if (c->frequency < 470000000) | ||
1229 | priv->ctrl.vhfbw7 = 1; | ||
1230 | else | ||
1231 | priv->ctrl.uhfbw8 = 0; | ||
1232 | type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV7; | ||
1233 | type |= F8MHZ; | ||
1234 | } else { | ||
1235 | if (c->frequency < 470000000) | ||
1236 | priv->ctrl.vhfbw7 = 0; | ||
1237 | else | ||
1238 | priv->ctrl.uhfbw8 = 1; | ||
1239 | type |= (priv->ctrl.vhfbw7 && priv->ctrl.uhfbw8) ? DTV78 : DTV8; | ||
1240 | type |= F8MHZ; | ||
1241 | } | ||
1242 | |||
1243 | /* All S-code tables need a 200kHz shift */ | ||
1244 | if (priv->ctrl.demod) { | ||
1245 | demod = priv->ctrl.demod; | ||
1246 | |||
1247 | /* | ||
1248 | * Newer firmwares require a 200 kHz offset only for ATSC | ||
1249 | */ | ||
1250 | if (type == ATSC || priv->firm_version < 0x0302) | ||
1251 | demod += 200; | ||
1252 | /* | ||
1253 | * The DTV7 S-code table needs a 700 kHz shift. | ||
1254 | * | ||
1255 | * DTV7 is only used in Australia. Germany or Italy may also | ||
1256 | * use this firmware after initialization, but a tune to a UHF | ||
1257 | * channel should then cause DTV78 to be used. | ||
1258 | * | ||
1259 | * Unfortunately, on real-field tests, the s-code offset | ||
1260 | * didn't work as expected, as reported by | ||
1261 | * Robert Lowery <rglowery@exemail.com.au> | ||
1262 | */ | ||
1263 | } | ||
1264 | |||
1265 | return generic_set_freq(fe, c->frequency, | ||
1266 | V4L2_TUNER_DIGITAL_TV, type, 0, demod); | ||
1267 | } | ||
1268 | |||
1269 | static int xc2028_sleep(struct dvb_frontend *fe) | ||
1270 | { | ||
1271 | struct xc2028_data *priv = fe->tuner_priv; | ||
1272 | int rc; | ||
1273 | |||
1274 | rc = check_device_status(priv); | ||
1275 | if (rc < 0) | ||
1276 | return rc; | ||
1277 | |||
1278 | /* Avoid firmware reload on slow devices or if PM disabled */ | ||
1279 | if (no_poweroff || priv->ctrl.disable_power_mgmt) | ||
1280 | return 0; | ||
1281 | |||
1282 | tuner_dbg("Putting xc2028/3028 into poweroff mode.\n"); | ||
1283 | if (debug > 1) { | ||
1284 | tuner_dbg("Printing sleep stack trace:\n"); | ||
1285 | dump_stack(); | ||
1286 | } | ||
1287 | |||
1288 | mutex_lock(&priv->lock); | ||
1289 | |||
1290 | if (priv->firm_version < 0x0202) | ||
1291 | rc = send_seq(priv, {0x00, XREG_POWER_DOWN, 0x00, 0x00}); | ||
1292 | else | ||
1293 | rc = send_seq(priv, {0x80, XREG_POWER_DOWN, 0x00, 0x00}); | ||
1294 | |||
1295 | priv->state = XC2028_SLEEP; | ||
1296 | |||
1297 | mutex_unlock(&priv->lock); | ||
1298 | |||
1299 | return rc; | ||
1300 | } | ||
1301 | |||
1302 | static int xc2028_dvb_release(struct dvb_frontend *fe) | ||
1303 | { | ||
1304 | struct xc2028_data *priv = fe->tuner_priv; | ||
1305 | |||
1306 | tuner_dbg("%s called\n", __func__); | ||
1307 | |||
1308 | mutex_lock(&xc2028_list_mutex); | ||
1309 | |||
1310 | /* only perform final cleanup if this is the last instance */ | ||
1311 | if (hybrid_tuner_report_instance_count(priv) == 1) { | ||
1312 | free_firmware(priv); | ||
1313 | kfree(priv->ctrl.fname); | ||
1314 | priv->ctrl.fname = NULL; | ||
1315 | } | ||
1316 | |||
1317 | if (priv) | ||
1318 | hybrid_tuner_release_state(priv); | ||
1319 | |||
1320 | mutex_unlock(&xc2028_list_mutex); | ||
1321 | |||
1322 | fe->tuner_priv = NULL; | ||
1323 | |||
1324 | return 0; | ||
1325 | } | ||
1326 | |||
1327 | static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency) | ||
1328 | { | ||
1329 | struct xc2028_data *priv = fe->tuner_priv; | ||
1330 | int rc; | ||
1331 | |||
1332 | tuner_dbg("%s called\n", __func__); | ||
1333 | |||
1334 | rc = check_device_status(priv); | ||
1335 | if (rc < 0) | ||
1336 | return rc; | ||
1337 | |||
1338 | *frequency = priv->frequency; | ||
1339 | |||
1340 | return 0; | ||
1341 | } | ||
1342 | |||
1343 | static void load_firmware_cb(const struct firmware *fw, | ||
1344 | void *context) | ||
1345 | { | ||
1346 | struct dvb_frontend *fe = context; | ||
1347 | struct xc2028_data *priv = fe->tuner_priv; | ||
1348 | int rc; | ||
1349 | |||
1350 | tuner_dbg("request_firmware_nowait(): %s\n", fw ? "OK" : "error"); | ||
1351 | if (!fw) { | ||
1352 | tuner_err("Could not load firmware %s.\n", priv->fname); | ||
1353 | priv->state = XC2028_NODEV; | ||
1354 | return; | ||
1355 | } | ||
1356 | |||
1357 | rc = load_all_firmwares(fe, fw); | ||
1358 | |||
1359 | release_firmware(fw); | ||
1360 | |||
1361 | if (rc < 0) | ||
1362 | return; | ||
1363 | priv->state = XC2028_SLEEP; | ||
1364 | } | ||
1365 | |||
1366 | static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg) | ||
1367 | { | ||
1368 | struct xc2028_data *priv = fe->tuner_priv; | ||
1369 | struct xc2028_ctrl *p = priv_cfg; | ||
1370 | int rc = 0; | ||
1371 | |||
1372 | tuner_dbg("%s called\n", __func__); | ||
1373 | |||
1374 | mutex_lock(&priv->lock); | ||
1375 | |||
1376 | /* | ||
1377 | * Copy the config data. | ||
1378 | * For the firmware name, keep a local copy of the string, | ||
1379 | * in order to avoid troubles during device release. | ||
1380 | */ | ||
1381 | if (priv->ctrl.fname) | ||
1382 | kfree(priv->ctrl.fname); | ||
1383 | memcpy(&priv->ctrl, p, sizeof(priv->ctrl)); | ||
1384 | if (p->fname) { | ||
1385 | priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL); | ||
1386 | if (priv->ctrl.fname == NULL) | ||
1387 | rc = -ENOMEM; | ||
1388 | } | ||
1389 | |||
1390 | /* | ||
1391 | * If firmware name changed, frees firmware. As free_firmware will | ||
1392 | * reset the status to NO_FIRMWARE, this forces a new request_firmware | ||
1393 | */ | ||
1394 | if (!firmware_name[0] && p->fname && | ||
1395 | priv->fname && strcmp(p->fname, priv->fname)) | ||
1396 | free_firmware(priv); | ||
1397 | |||
1398 | if (priv->ctrl.max_len < 9) | ||
1399 | priv->ctrl.max_len = 13; | ||
1400 | |||
1401 | if (priv->state == XC2028_NO_FIRMWARE) { | ||
1402 | if (!firmware_name[0]) | ||
1403 | priv->fname = priv->ctrl.fname; | ||
1404 | else | ||
1405 | priv->fname = firmware_name; | ||
1406 | |||
1407 | rc = request_firmware_nowait(THIS_MODULE, 1, | ||
1408 | priv->fname, | ||
1409 | priv->i2c_props.adap->dev.parent, | ||
1410 | GFP_KERNEL, | ||
1411 | fe, load_firmware_cb); | ||
1412 | if (rc < 0) { | ||
1413 | tuner_err("Failed to request firmware %s\n", | ||
1414 | priv->fname); | ||
1415 | priv->state = XC2028_NODEV; | ||
1416 | } else | ||
1417 | priv->state = XC2028_WAITING_FIRMWARE; | ||
1418 | } | ||
1419 | mutex_unlock(&priv->lock); | ||
1420 | |||
1421 | return rc; | ||
1422 | } | ||
1423 | |||
1424 | static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = { | ||
1425 | .info = { | ||
1426 | .name = "Xceive XC3028", | ||
1427 | .frequency_min = 42000000, | ||
1428 | .frequency_max = 864000000, | ||
1429 | .frequency_step = 50000, | ||
1430 | }, | ||
1431 | |||
1432 | .set_config = xc2028_set_config, | ||
1433 | .set_analog_params = xc2028_set_analog_freq, | ||
1434 | .release = xc2028_dvb_release, | ||
1435 | .get_frequency = xc2028_get_frequency, | ||
1436 | .get_rf_strength = xc2028_signal, | ||
1437 | .get_afc = xc2028_get_afc, | ||
1438 | .set_params = xc2028_set_params, | ||
1439 | .sleep = xc2028_sleep, | ||
1440 | }; | ||
1441 | |||
1442 | struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, | ||
1443 | struct xc2028_config *cfg) | ||
1444 | { | ||
1445 | struct xc2028_data *priv; | ||
1446 | int instance; | ||
1447 | |||
1448 | if (debug) | ||
1449 | printk(KERN_DEBUG "xc2028: Xcv2028/3028 init called!\n"); | ||
1450 | |||
1451 | if (NULL == cfg) | ||
1452 | return NULL; | ||
1453 | |||
1454 | if (!fe) { | ||
1455 | printk(KERN_ERR "xc2028: No frontend!\n"); | ||
1456 | return NULL; | ||
1457 | } | ||
1458 | |||
1459 | mutex_lock(&xc2028_list_mutex); | ||
1460 | |||
1461 | instance = hybrid_tuner_request_state(struct xc2028_data, priv, | ||
1462 | hybrid_tuner_instance_list, | ||
1463 | cfg->i2c_adap, cfg->i2c_addr, | ||
1464 | "xc2028"); | ||
1465 | switch (instance) { | ||
1466 | case 0: | ||
1467 | /* memory allocation failure */ | ||
1468 | goto fail; | ||
1469 | break; | ||
1470 | case 1: | ||
1471 | /* new tuner instance */ | ||
1472 | priv->ctrl.max_len = 13; | ||
1473 | |||
1474 | mutex_init(&priv->lock); | ||
1475 | |||
1476 | fe->tuner_priv = priv; | ||
1477 | break; | ||
1478 | case 2: | ||
1479 | /* existing tuner instance */ | ||
1480 | fe->tuner_priv = priv; | ||
1481 | break; | ||
1482 | } | ||
1483 | |||
1484 | memcpy(&fe->ops.tuner_ops, &xc2028_dvb_tuner_ops, | ||
1485 | sizeof(xc2028_dvb_tuner_ops)); | ||
1486 | |||
1487 | tuner_info("type set to %s\n", "XCeive xc2028/xc3028 tuner"); | ||
1488 | |||
1489 | if (cfg->ctrl) | ||
1490 | xc2028_set_config(fe, cfg->ctrl); | ||
1491 | |||
1492 | mutex_unlock(&xc2028_list_mutex); | ||
1493 | |||
1494 | return fe; | ||
1495 | fail: | ||
1496 | mutex_unlock(&xc2028_list_mutex); | ||
1497 | |||
1498 | xc2028_dvb_release(fe); | ||
1499 | return NULL; | ||
1500 | } | ||
1501 | |||
1502 | EXPORT_SYMBOL(xc2028_attach); | ||
1503 | |||
1504 | MODULE_DESCRIPTION("Xceive xc2028/xc3028 tuner driver"); | ||
1505 | MODULE_AUTHOR("Michel Ludwig <michel.ludwig@gmail.com>"); | ||
1506 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); | ||
1507 | MODULE_LICENSE("GPL"); | ||
1508 | MODULE_FIRMWARE(XC2028_DEFAULT_FIRMWARE); | ||
1509 | MODULE_FIRMWARE(XC3028L_DEFAULT_FIRMWARE); | ||
diff --git a/drivers/media/tuners/tuner-xc2028.h b/drivers/media/tuners/tuner-xc2028.h new file mode 100644 index 000000000000..9ebfb2d0ff14 --- /dev/null +++ b/drivers/media/tuners/tuner-xc2028.h | |||
@@ -0,0 +1,72 @@ | |||
1 | /* tuner-xc2028 | ||
2 | * | ||
3 | * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org) | ||
4 | * This code is placed under the terms of the GNU General Public License v2 | ||
5 | */ | ||
6 | |||
7 | #ifndef __TUNER_XC2028_H__ | ||
8 | #define __TUNER_XC2028_H__ | ||
9 | |||
10 | #include "dvb_frontend.h" | ||
11 | |||
12 | #define XC2028_DEFAULT_FIRMWARE "xc3028-v27.fw" | ||
13 | #define XC3028L_DEFAULT_FIRMWARE "xc3028L-v36.fw" | ||
14 | |||
15 | /* Dmoduler IF (kHz) */ | ||
16 | #define XC3028_FE_DEFAULT 0 /* Don't load SCODE */ | ||
17 | #define XC3028_FE_LG60 6000 | ||
18 | #define XC3028_FE_ATI638 6380 | ||
19 | #define XC3028_FE_OREN538 5380 | ||
20 | #define XC3028_FE_OREN36 3600 | ||
21 | #define XC3028_FE_TOYOTA388 3880 | ||
22 | #define XC3028_FE_TOYOTA794 7940 | ||
23 | #define XC3028_FE_DIBCOM52 5200 | ||
24 | #define XC3028_FE_ZARLINK456 4560 | ||
25 | #define XC3028_FE_CHINA 5200 | ||
26 | |||
27 | enum firmware_type { | ||
28 | XC2028_AUTO = 0, /* By default, auto-detects */ | ||
29 | XC2028_D2633, | ||
30 | XC2028_D2620, | ||
31 | }; | ||
32 | |||
33 | struct xc2028_ctrl { | ||
34 | char *fname; | ||
35 | int max_len; | ||
36 | int msleep; | ||
37 | unsigned int scode_table; | ||
38 | unsigned int mts :1; | ||
39 | unsigned int input1:1; | ||
40 | unsigned int vhfbw7:1; | ||
41 | unsigned int uhfbw8:1; | ||
42 | unsigned int disable_power_mgmt:1; | ||
43 | unsigned int read_not_reliable:1; | ||
44 | unsigned int demod; | ||
45 | enum firmware_type type:2; | ||
46 | }; | ||
47 | |||
48 | struct xc2028_config { | ||
49 | struct i2c_adapter *i2c_adap; | ||
50 | u8 i2c_addr; | ||
51 | struct xc2028_ctrl *ctrl; | ||
52 | }; | ||
53 | |||
54 | /* xc2028 commands for callback */ | ||
55 | #define XC2028_TUNER_RESET 0 | ||
56 | #define XC2028_RESET_CLK 1 | ||
57 | #define XC2028_I2C_FLUSH 2 | ||
58 | |||
59 | #if defined(CONFIG_MEDIA_TUNER_XC2028) || (defined(CONFIG_MEDIA_TUNER_XC2028_MODULE) && defined(MODULE)) | ||
60 | extern struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, | ||
61 | struct xc2028_config *cfg); | ||
62 | #else | ||
63 | static inline struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe, | ||
64 | struct xc2028_config *cfg) | ||
65 | { | ||
66 | printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n", | ||
67 | __func__); | ||
68 | return NULL; | ||
69 | } | ||
70 | #endif | ||
71 | |||
72 | #endif /* __TUNER_XC2028_H__ */ | ||
diff --git a/drivers/media/tuners/xc4000.c b/drivers/media/tuners/xc4000.c new file mode 100644 index 000000000000..4937712278f6 --- /dev/null +++ b/drivers/media/tuners/xc4000.c | |||
@@ -0,0 +1,1757 @@ | |||
1 | /* | ||
2 | * Driver for Xceive XC4000 "QAM/8VSB single chip tuner" | ||
3 | * | ||
4 | * Copyright (c) 2007 Xceive Corporation | ||
5 | * Copyright (c) 2007 Steven Toth <stoth@linuxtv.org> | ||
6 | * Copyright (c) 2009 Devin Heitmueller <dheitmueller@kernellabs.com> | ||
7 | * Copyright (c) 2009 Davide Ferri <d.ferri@zero11.it> | ||
8 | * Copyright (c) 2010 Istvan Varga <istvan_v@mailbox.hu> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
23 | */ | ||
24 | |||
25 | #include <linux/module.h> | ||
26 | #include <linux/moduleparam.h> | ||
27 | #include <linux/videodev2.h> | ||
28 | #include <linux/delay.h> | ||
29 | #include <linux/dvb/frontend.h> | ||
30 | #include <linux/i2c.h> | ||
31 | #include <linux/mutex.h> | ||
32 | #include <asm/unaligned.h> | ||
33 | |||
34 | #include "dvb_frontend.h" | ||
35 | |||
36 | #include "xc4000.h" | ||
37 | #include "tuner-i2c.h" | ||
38 | #include "tuner-xc2028-types.h" | ||
39 | |||
40 | static int debug; | ||
41 | module_param(debug, int, 0644); | ||
42 | MODULE_PARM_DESC(debug, "Debugging level (0 to 2, default: 0 (off))."); | ||
43 | |||
44 | static int no_poweroff; | ||
45 | module_param(no_poweroff, int, 0644); | ||
46 | MODULE_PARM_DESC(no_poweroff, "Power management (1: disabled, 2: enabled, " | ||
47 | "0 (default): use device-specific default mode)."); | ||
48 | |||
49 | static int audio_std; | ||
50 | module_param(audio_std, int, 0644); | ||
51 | MODULE_PARM_DESC(audio_std, "Audio standard. XC4000 audio decoder explicitly " | ||
52 | "needs to know what audio standard is needed for some video standards " | ||
53 | "with audio A2 or NICAM. The valid settings are a sum of:\n" | ||
54 | " 1: use NICAM/B or A2/B instead of NICAM/A or A2/A\n" | ||
55 | " 2: use A2 instead of NICAM or BTSC\n" | ||
56 | " 4: use SECAM/K3 instead of K1\n" | ||
57 | " 8: use PAL-D/K audio for SECAM-D/K\n" | ||
58 | "16: use FM radio input 1 instead of input 2\n" | ||
59 | "32: use mono audio (the lower three bits are ignored)"); | ||
60 | |||
61 | static char firmware_name[30]; | ||
62 | module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0); | ||
63 | MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the " | ||
64 | "default firmware name."); | ||
65 | |||
66 | static DEFINE_MUTEX(xc4000_list_mutex); | ||
67 | static LIST_HEAD(hybrid_tuner_instance_list); | ||
68 | |||
69 | #define dprintk(level, fmt, arg...) if (debug >= level) \ | ||
70 | printk(KERN_INFO "%s: " fmt, "xc4000", ## arg) | ||
71 | |||
72 | /* struct for storing firmware table */ | ||
73 | struct firmware_description { | ||
74 | unsigned int type; | ||
75 | v4l2_std_id id; | ||
76 | __u16 int_freq; | ||
77 | unsigned char *ptr; | ||
78 | unsigned int size; | ||
79 | }; | ||
80 | |||
81 | struct firmware_properties { | ||
82 | unsigned int type; | ||
83 | v4l2_std_id id; | ||
84 | v4l2_std_id std_req; | ||
85 | __u16 int_freq; | ||
86 | unsigned int scode_table; | ||
87 | int scode_nr; | ||
88 | }; | ||
89 | |||
90 | struct xc4000_priv { | ||
91 | struct tuner_i2c_props i2c_props; | ||
92 | struct list_head hybrid_tuner_instance_list; | ||
93 | struct firmware_description *firm; | ||
94 | int firm_size; | ||
95 | u32 if_khz; | ||
96 | u32 freq_hz; | ||
97 | u32 bandwidth; | ||
98 | u8 video_standard; | ||
99 | u8 rf_mode; | ||
100 | u8 default_pm; | ||
101 | u8 dvb_amplitude; | ||
102 | u8 set_smoothedcvbs; | ||
103 | u8 ignore_i2c_write_errors; | ||
104 | __u16 firm_version; | ||
105 | struct firmware_properties cur_fw; | ||
106 | __u16 hwmodel; | ||
107 | __u16 hwvers; | ||
108 | struct mutex lock; | ||
109 | }; | ||
110 | |||
111 | #define XC4000_AUDIO_STD_B 1 | ||
112 | #define XC4000_AUDIO_STD_A2 2 | ||
113 | #define XC4000_AUDIO_STD_K3 4 | ||
114 | #define XC4000_AUDIO_STD_L 8 | ||
115 | #define XC4000_AUDIO_STD_INPUT1 16 | ||
116 | #define XC4000_AUDIO_STD_MONO 32 | ||
117 | |||
118 | #define XC4000_DEFAULT_FIRMWARE "dvb-fe-xc4000-1.4.fw" | ||
119 | |||
120 | /* Misc Defines */ | ||
121 | #define MAX_TV_STANDARD 24 | ||
122 | #define XC_MAX_I2C_WRITE_LENGTH 64 | ||
123 | #define XC_POWERED_DOWN 0x80000000U | ||
124 | |||
125 | /* Signal Types */ | ||
126 | #define XC_RF_MODE_AIR 0 | ||
127 | #define XC_RF_MODE_CABLE 1 | ||
128 | |||
129 | /* Product id */ | ||
130 | #define XC_PRODUCT_ID_FW_NOT_LOADED 0x2000 | ||
131 | #define XC_PRODUCT_ID_XC4000 0x0FA0 | ||
132 | #define XC_PRODUCT_ID_XC4100 0x1004 | ||
133 | |||
134 | /* Registers (Write-only) */ | ||
135 | #define XREG_INIT 0x00 | ||
136 | #define XREG_VIDEO_MODE 0x01 | ||
137 | #define XREG_AUDIO_MODE 0x02 | ||
138 | #define XREG_RF_FREQ 0x03 | ||
139 | #define XREG_D_CODE 0x04 | ||
140 | #define XREG_DIRECTSITTING_MODE 0x05 | ||
141 | #define XREG_SEEK_MODE 0x06 | ||
142 | #define XREG_POWER_DOWN 0x08 | ||
143 | #define XREG_SIGNALSOURCE 0x0A | ||
144 | #define XREG_SMOOTHEDCVBS 0x0E | ||
145 | #define XREG_AMPLITUDE 0x10 | ||
146 | |||
147 | /* Registers (Read-only) */ | ||
148 | #define XREG_ADC_ENV 0x00 | ||
149 | #define XREG_QUALITY 0x01 | ||
150 | #define XREG_FRAME_LINES 0x02 | ||
151 | #define XREG_HSYNC_FREQ 0x03 | ||
152 | #define XREG_LOCK 0x04 | ||
153 | #define XREG_FREQ_ERROR 0x05 | ||
154 | #define XREG_SNR 0x06 | ||
155 | #define XREG_VERSION 0x07 | ||
156 | #define XREG_PRODUCT_ID 0x08 | ||
157 | #define XREG_SIGNAL_LEVEL 0x0A | ||
158 | #define XREG_NOISE_LEVEL 0x0B | ||
159 | |||
160 | /* | ||
161 | Basic firmware description. This will remain with | ||
162 | the driver for documentation purposes. | ||
163 | |||
164 | This represents an I2C firmware file encoded as a | ||
165 | string of unsigned char. Format is as follows: | ||
166 | |||
167 | char[0 ]=len0_MSB -> len = len_MSB * 256 + len_LSB | ||
168 | char[1 ]=len0_LSB -> length of first write transaction | ||
169 | char[2 ]=data0 -> first byte to be sent | ||
170 | char[3 ]=data1 | ||
171 | char[4 ]=data2 | ||
172 | char[ ]=... | ||
173 | char[M ]=dataN -> last byte to be sent | ||
174 | char[M+1]=len1_MSB -> len = len_MSB * 256 + len_LSB | ||
175 | char[M+2]=len1_LSB -> length of second write transaction | ||
176 | char[M+3]=data0 | ||
177 | char[M+4]=data1 | ||
178 | ... | ||
179 | etc. | ||
180 | |||
181 | The [len] value should be interpreted as follows: | ||
182 | |||
183 | len= len_MSB _ len_LSB | ||
184 | len=1111_1111_1111_1111 : End of I2C_SEQUENCE | ||
185 | len=0000_0000_0000_0000 : Reset command: Do hardware reset | ||
186 | len=0NNN_NNNN_NNNN_NNNN : Normal transaction: number of bytes = {1:32767) | ||
187 | len=1WWW_WWWW_WWWW_WWWW : Wait command: wait for {1:32767} ms | ||
188 | |||
189 | For the RESET and WAIT commands, the two following bytes will contain | ||
190 | immediately the length of the following transaction. | ||
191 | */ | ||
192 | |||
193 | struct XC_TV_STANDARD { | ||
194 | const char *Name; | ||
195 | u16 audio_mode; | ||
196 | u16 video_mode; | ||
197 | u16 int_freq; | ||
198 | }; | ||
199 | |||
200 | /* Tuner standards */ | ||
201 | #define XC4000_MN_NTSC_PAL_BTSC 0 | ||
202 | #define XC4000_MN_NTSC_PAL_A2 1 | ||
203 | #define XC4000_MN_NTSC_PAL_EIAJ 2 | ||
204 | #define XC4000_MN_NTSC_PAL_Mono 3 | ||
205 | #define XC4000_BG_PAL_A2 4 | ||
206 | #define XC4000_BG_PAL_NICAM 5 | ||
207 | #define XC4000_BG_PAL_MONO 6 | ||
208 | #define XC4000_I_PAL_NICAM 7 | ||
209 | #define XC4000_I_PAL_NICAM_MONO 8 | ||
210 | #define XC4000_DK_PAL_A2 9 | ||
211 | #define XC4000_DK_PAL_NICAM 10 | ||
212 | #define XC4000_DK_PAL_MONO 11 | ||
213 | #define XC4000_DK_SECAM_A2DK1 12 | ||
214 | #define XC4000_DK_SECAM_A2LDK3 13 | ||
215 | #define XC4000_DK_SECAM_A2MONO 14 | ||
216 | #define XC4000_DK_SECAM_NICAM 15 | ||
217 | #define XC4000_L_SECAM_NICAM 16 | ||
218 | #define XC4000_LC_SECAM_NICAM 17 | ||
219 | #define XC4000_DTV6 18 | ||
220 | #define XC4000_DTV8 19 | ||
221 | #define XC4000_DTV7_8 20 | ||
222 | #define XC4000_DTV7 21 | ||
223 | #define XC4000_FM_Radio_INPUT2 22 | ||
224 | #define XC4000_FM_Radio_INPUT1 23 | ||
225 | |||
226 | static struct XC_TV_STANDARD xc4000_standard[MAX_TV_STANDARD] = { | ||
227 | {"M/N-NTSC/PAL-BTSC", 0x0000, 0x80A0, 4500}, | ||
228 | {"M/N-NTSC/PAL-A2", 0x0000, 0x80A0, 4600}, | ||
229 | {"M/N-NTSC/PAL-EIAJ", 0x0040, 0x80A0, 4500}, | ||
230 | {"M/N-NTSC/PAL-Mono", 0x0078, 0x80A0, 4500}, | ||
231 | {"B/G-PAL-A2", 0x0000, 0x8159, 5640}, | ||
232 | {"B/G-PAL-NICAM", 0x0004, 0x8159, 5740}, | ||
233 | {"B/G-PAL-MONO", 0x0078, 0x8159, 5500}, | ||
234 | {"I-PAL-NICAM", 0x0080, 0x8049, 6240}, | ||
235 | {"I-PAL-NICAM-MONO", 0x0078, 0x8049, 6000}, | ||
236 | {"D/K-PAL-A2", 0x0000, 0x8049, 6380}, | ||
237 | {"D/K-PAL-NICAM", 0x0080, 0x8049, 6200}, | ||
238 | {"D/K-PAL-MONO", 0x0078, 0x8049, 6500}, | ||
239 | {"D/K-SECAM-A2 DK1", 0x0000, 0x8049, 6340}, | ||
240 | {"D/K-SECAM-A2 L/DK3", 0x0000, 0x8049, 6000}, | ||
241 | {"D/K-SECAM-A2 MONO", 0x0078, 0x8049, 6500}, | ||
242 | {"D/K-SECAM-NICAM", 0x0080, 0x8049, 6200}, | ||
243 | {"L-SECAM-NICAM", 0x8080, 0x0009, 6200}, | ||
244 | {"L'-SECAM-NICAM", 0x8080, 0x4009, 6200}, | ||
245 | {"DTV6", 0x00C0, 0x8002, 0}, | ||
246 | {"DTV8", 0x00C0, 0x800B, 0}, | ||
247 | {"DTV7/8", 0x00C0, 0x801B, 0}, | ||
248 | {"DTV7", 0x00C0, 0x8007, 0}, | ||
249 | {"FM Radio-INPUT2", 0x0008, 0x9800, 10700}, | ||
250 | {"FM Radio-INPUT1", 0x0008, 0x9000, 10700} | ||
251 | }; | ||
252 | |||
253 | static int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val); | ||
254 | static int xc4000_tuner_reset(struct dvb_frontend *fe); | ||
255 | static void xc_debug_dump(struct xc4000_priv *priv); | ||
256 | |||
257 | static int xc_send_i2c_data(struct xc4000_priv *priv, u8 *buf, int len) | ||
258 | { | ||
259 | struct i2c_msg msg = { .addr = priv->i2c_props.addr, | ||
260 | .flags = 0, .buf = buf, .len = len }; | ||
261 | if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { | ||
262 | if (priv->ignore_i2c_write_errors == 0) { | ||
263 | printk(KERN_ERR "xc4000: I2C write failed (len=%i)\n", | ||
264 | len); | ||
265 | if (len == 4) { | ||
266 | printk(KERN_ERR "bytes %*ph\n", 4, buf); | ||
267 | } | ||
268 | return -EREMOTEIO; | ||
269 | } | ||
270 | } | ||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | static int xc4000_tuner_reset(struct dvb_frontend *fe) | ||
275 | { | ||
276 | struct xc4000_priv *priv = fe->tuner_priv; | ||
277 | int ret; | ||
278 | |||
279 | dprintk(1, "%s()\n", __func__); | ||
280 | |||
281 | if (fe->callback) { | ||
282 | ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ? | ||
283 | fe->dvb->priv : | ||
284 | priv->i2c_props.adap->algo_data, | ||
285 | DVB_FRONTEND_COMPONENT_TUNER, | ||
286 | XC4000_TUNER_RESET, 0); | ||
287 | if (ret) { | ||
288 | printk(KERN_ERR "xc4000: reset failed\n"); | ||
289 | return -EREMOTEIO; | ||
290 | } | ||
291 | } else { | ||
292 | printk(KERN_ERR "xc4000: no tuner reset callback function, " | ||
293 | "fatal\n"); | ||
294 | return -EINVAL; | ||
295 | } | ||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | static int xc_write_reg(struct xc4000_priv *priv, u16 regAddr, u16 i2cData) | ||
300 | { | ||
301 | u8 buf[4]; | ||
302 | int result; | ||
303 | |||
304 | buf[0] = (regAddr >> 8) & 0xFF; | ||
305 | buf[1] = regAddr & 0xFF; | ||
306 | buf[2] = (i2cData >> 8) & 0xFF; | ||
307 | buf[3] = i2cData & 0xFF; | ||
308 | result = xc_send_i2c_data(priv, buf, 4); | ||
309 | |||
310 | return result; | ||
311 | } | ||
312 | |||
313 | static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence) | ||
314 | { | ||
315 | struct xc4000_priv *priv = fe->tuner_priv; | ||
316 | |||
317 | int i, nbytes_to_send, result; | ||
318 | unsigned int len, pos, index; | ||
319 | u8 buf[XC_MAX_I2C_WRITE_LENGTH]; | ||
320 | |||
321 | index = 0; | ||
322 | while ((i2c_sequence[index] != 0xFF) || | ||
323 | (i2c_sequence[index + 1] != 0xFF)) { | ||
324 | len = i2c_sequence[index] * 256 + i2c_sequence[index+1]; | ||
325 | if (len == 0x0000) { | ||
326 | /* RESET command */ | ||
327 | /* NOTE: this is ignored, as the reset callback was */ | ||
328 | /* already called by check_firmware() */ | ||
329 | index += 2; | ||
330 | } else if (len & 0x8000) { | ||
331 | /* WAIT command */ | ||
332 | msleep(len & 0x7FFF); | ||
333 | index += 2; | ||
334 | } else { | ||
335 | /* Send i2c data whilst ensuring individual transactions | ||
336 | * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes. | ||
337 | */ | ||
338 | index += 2; | ||
339 | buf[0] = i2c_sequence[index]; | ||
340 | buf[1] = i2c_sequence[index + 1]; | ||
341 | pos = 2; | ||
342 | while (pos < len) { | ||
343 | if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2) | ||
344 | nbytes_to_send = | ||
345 | XC_MAX_I2C_WRITE_LENGTH; | ||
346 | else | ||
347 | nbytes_to_send = (len - pos + 2); | ||
348 | for (i = 2; i < nbytes_to_send; i++) { | ||
349 | buf[i] = i2c_sequence[index + pos + | ||
350 | i - 2]; | ||
351 | } | ||
352 | result = xc_send_i2c_data(priv, buf, | ||
353 | nbytes_to_send); | ||
354 | |||
355 | if (result != 0) | ||
356 | return result; | ||
357 | |||
358 | pos += nbytes_to_send - 2; | ||
359 | } | ||
360 | index += len; | ||
361 | } | ||
362 | } | ||
363 | return 0; | ||
364 | } | ||
365 | |||
366 | static int xc_set_tv_standard(struct xc4000_priv *priv, | ||
367 | u16 video_mode, u16 audio_mode) | ||
368 | { | ||
369 | int ret; | ||
370 | dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, video_mode, audio_mode); | ||
371 | dprintk(1, "%s() Standard = %s\n", | ||
372 | __func__, | ||
373 | xc4000_standard[priv->video_standard].Name); | ||
374 | |||
375 | /* Don't complain when the request fails because of i2c stretching */ | ||
376 | priv->ignore_i2c_write_errors = 1; | ||
377 | |||
378 | ret = xc_write_reg(priv, XREG_VIDEO_MODE, video_mode); | ||
379 | if (ret == 0) | ||
380 | ret = xc_write_reg(priv, XREG_AUDIO_MODE, audio_mode); | ||
381 | |||
382 | priv->ignore_i2c_write_errors = 0; | ||
383 | |||
384 | return ret; | ||
385 | } | ||
386 | |||
387 | static int xc_set_signal_source(struct xc4000_priv *priv, u16 rf_mode) | ||
388 | { | ||
389 | dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode, | ||
390 | rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE"); | ||
391 | |||
392 | if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE)) { | ||
393 | rf_mode = XC_RF_MODE_CABLE; | ||
394 | printk(KERN_ERR | ||
395 | "%s(), Invalid mode, defaulting to CABLE", | ||
396 | __func__); | ||
397 | } | ||
398 | return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode); | ||
399 | } | ||
400 | |||
401 | static const struct dvb_tuner_ops xc4000_tuner_ops; | ||
402 | |||
403 | static int xc_set_rf_frequency(struct xc4000_priv *priv, u32 freq_hz) | ||
404 | { | ||
405 | u16 freq_code; | ||
406 | |||
407 | dprintk(1, "%s(%u)\n", __func__, freq_hz); | ||
408 | |||
409 | if ((freq_hz > xc4000_tuner_ops.info.frequency_max) || | ||
410 | (freq_hz < xc4000_tuner_ops.info.frequency_min)) | ||
411 | return -EINVAL; | ||
412 | |||
413 | freq_code = (u16)(freq_hz / 15625); | ||
414 | |||
415 | /* WAS: Starting in firmware version 1.1.44, Xceive recommends using the | ||
416 | FINERFREQ for all normal tuning (the doc indicates reg 0x03 should | ||
417 | only be used for fast scanning for channel lock) */ | ||
418 | /* WAS: XREG_FINERFREQ */ | ||
419 | return xc_write_reg(priv, XREG_RF_FREQ, freq_code); | ||
420 | } | ||
421 | |||
422 | static int xc_get_adc_envelope(struct xc4000_priv *priv, u16 *adc_envelope) | ||
423 | { | ||
424 | return xc4000_readreg(priv, XREG_ADC_ENV, adc_envelope); | ||
425 | } | ||
426 | |||
427 | static int xc_get_frequency_error(struct xc4000_priv *priv, u32 *freq_error_hz) | ||
428 | { | ||
429 | int result; | ||
430 | u16 regData; | ||
431 | u32 tmp; | ||
432 | |||
433 | result = xc4000_readreg(priv, XREG_FREQ_ERROR, ®Data); | ||
434 | if (result != 0) | ||
435 | return result; | ||
436 | |||
437 | tmp = (u32)regData & 0xFFFFU; | ||
438 | tmp = (tmp < 0x8000U ? tmp : 0x10000U - tmp); | ||
439 | (*freq_error_hz) = tmp * 15625; | ||
440 | return result; | ||
441 | } | ||
442 | |||
443 | static int xc_get_lock_status(struct xc4000_priv *priv, u16 *lock_status) | ||
444 | { | ||
445 | return xc4000_readreg(priv, XREG_LOCK, lock_status); | ||
446 | } | ||
447 | |||
448 | static int xc_get_version(struct xc4000_priv *priv, | ||
449 | u8 *hw_majorversion, u8 *hw_minorversion, | ||
450 | u8 *fw_majorversion, u8 *fw_minorversion) | ||
451 | { | ||
452 | u16 data; | ||
453 | int result; | ||
454 | |||
455 | result = xc4000_readreg(priv, XREG_VERSION, &data); | ||
456 | if (result != 0) | ||
457 | return result; | ||
458 | |||
459 | (*hw_majorversion) = (data >> 12) & 0x0F; | ||
460 | (*hw_minorversion) = (data >> 8) & 0x0F; | ||
461 | (*fw_majorversion) = (data >> 4) & 0x0F; | ||
462 | (*fw_minorversion) = data & 0x0F; | ||
463 | |||
464 | return 0; | ||
465 | } | ||
466 | |||
467 | static int xc_get_hsync_freq(struct xc4000_priv *priv, u32 *hsync_freq_hz) | ||
468 | { | ||
469 | u16 regData; | ||
470 | int result; | ||
471 | |||
472 | result = xc4000_readreg(priv, XREG_HSYNC_FREQ, ®Data); | ||
473 | if (result != 0) | ||
474 | return result; | ||
475 | |||
476 | (*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100; | ||
477 | return result; | ||
478 | } | ||
479 | |||
480 | static int xc_get_frame_lines(struct xc4000_priv *priv, u16 *frame_lines) | ||
481 | { | ||
482 | return xc4000_readreg(priv, XREG_FRAME_LINES, frame_lines); | ||
483 | } | ||
484 | |||
485 | static int xc_get_quality(struct xc4000_priv *priv, u16 *quality) | ||
486 | { | ||
487 | return xc4000_readreg(priv, XREG_QUALITY, quality); | ||
488 | } | ||
489 | |||
490 | static int xc_get_signal_level(struct xc4000_priv *priv, u16 *signal) | ||
491 | { | ||
492 | return xc4000_readreg(priv, XREG_SIGNAL_LEVEL, signal); | ||
493 | } | ||
494 | |||
495 | static int xc_get_noise_level(struct xc4000_priv *priv, u16 *noise) | ||
496 | { | ||
497 | return xc4000_readreg(priv, XREG_NOISE_LEVEL, noise); | ||
498 | } | ||
499 | |||
500 | static u16 xc_wait_for_lock(struct xc4000_priv *priv) | ||
501 | { | ||
502 | u16 lock_state = 0; | ||
503 | int watchdog_count = 40; | ||
504 | |||
505 | while ((lock_state == 0) && (watchdog_count > 0)) { | ||
506 | xc_get_lock_status(priv, &lock_state); | ||
507 | if (lock_state != 1) { | ||
508 | msleep(5); | ||
509 | watchdog_count--; | ||
510 | } | ||
511 | } | ||
512 | return lock_state; | ||
513 | } | ||
514 | |||
515 | static int xc_tune_channel(struct xc4000_priv *priv, u32 freq_hz) | ||
516 | { | ||
517 | int found = 1; | ||
518 | int result; | ||
519 | |||
520 | dprintk(1, "%s(%u)\n", __func__, freq_hz); | ||
521 | |||
522 | /* Don't complain when the request fails because of i2c stretching */ | ||
523 | priv->ignore_i2c_write_errors = 1; | ||
524 | result = xc_set_rf_frequency(priv, freq_hz); | ||
525 | priv->ignore_i2c_write_errors = 0; | ||
526 | |||
527 | if (result != 0) | ||
528 | return 0; | ||
529 | |||
530 | /* wait for lock only in analog TV mode */ | ||
531 | if ((priv->cur_fw.type & (FM | DTV6 | DTV7 | DTV78 | DTV8)) == 0) { | ||
532 | if (xc_wait_for_lock(priv) != 1) | ||
533 | found = 0; | ||
534 | } | ||
535 | |||
536 | /* Wait for stats to stabilize. | ||
537 | * Frame Lines needs two frame times after initial lock | ||
538 | * before it is valid. | ||
539 | */ | ||
540 | msleep(debug ? 100 : 10); | ||
541 | |||
542 | if (debug) | ||
543 | xc_debug_dump(priv); | ||
544 | |||
545 | return found; | ||
546 | } | ||
547 | |||
548 | static int xc4000_readreg(struct xc4000_priv *priv, u16 reg, u16 *val) | ||
549 | { | ||
550 | u8 buf[2] = { reg >> 8, reg & 0xff }; | ||
551 | u8 bval[2] = { 0, 0 }; | ||
552 | struct i2c_msg msg[2] = { | ||
553 | { .addr = priv->i2c_props.addr, | ||
554 | .flags = 0, .buf = &buf[0], .len = 2 }, | ||
555 | { .addr = priv->i2c_props.addr, | ||
556 | .flags = I2C_M_RD, .buf = &bval[0], .len = 2 }, | ||
557 | }; | ||
558 | |||
559 | if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) { | ||
560 | printk(KERN_ERR "xc4000: I2C read failed\n"); | ||
561 | return -EREMOTEIO; | ||
562 | } | ||
563 | |||
564 | *val = (bval[0] << 8) | bval[1]; | ||
565 | return 0; | ||
566 | } | ||
567 | |||
568 | #define dump_firm_type(t) dump_firm_type_and_int_freq(t, 0) | ||
569 | static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq) | ||
570 | { | ||
571 | if (type & BASE) | ||
572 | printk(KERN_CONT "BASE "); | ||
573 | if (type & INIT1) | ||
574 | printk(KERN_CONT "INIT1 "); | ||
575 | if (type & F8MHZ) | ||
576 | printk(KERN_CONT "F8MHZ "); | ||
577 | if (type & MTS) | ||
578 | printk(KERN_CONT "MTS "); | ||
579 | if (type & D2620) | ||
580 | printk(KERN_CONT "D2620 "); | ||
581 | if (type & D2633) | ||
582 | printk(KERN_CONT "D2633 "); | ||
583 | if (type & DTV6) | ||
584 | printk(KERN_CONT "DTV6 "); | ||
585 | if (type & QAM) | ||
586 | printk(KERN_CONT "QAM "); | ||
587 | if (type & DTV7) | ||
588 | printk(KERN_CONT "DTV7 "); | ||
589 | if (type & DTV78) | ||
590 | printk(KERN_CONT "DTV78 "); | ||
591 | if (type & DTV8) | ||
592 | printk(KERN_CONT "DTV8 "); | ||
593 | if (type & FM) | ||
594 | printk(KERN_CONT "FM "); | ||
595 | if (type & INPUT1) | ||
596 | printk(KERN_CONT "INPUT1 "); | ||
597 | if (type & LCD) | ||
598 | printk(KERN_CONT "LCD "); | ||
599 | if (type & NOGD) | ||
600 | printk(KERN_CONT "NOGD "); | ||
601 | if (type & MONO) | ||
602 | printk(KERN_CONT "MONO "); | ||
603 | if (type & ATSC) | ||
604 | printk(KERN_CONT "ATSC "); | ||
605 | if (type & IF) | ||
606 | printk(KERN_CONT "IF "); | ||
607 | if (type & LG60) | ||
608 | printk(KERN_CONT "LG60 "); | ||
609 | if (type & ATI638) | ||
610 | printk(KERN_CONT "ATI638 "); | ||
611 | if (type & OREN538) | ||
612 | printk(KERN_CONT "OREN538 "); | ||
613 | if (type & OREN36) | ||
614 | printk(KERN_CONT "OREN36 "); | ||
615 | if (type & TOYOTA388) | ||
616 | printk(KERN_CONT "TOYOTA388 "); | ||
617 | if (type & TOYOTA794) | ||
618 | printk(KERN_CONT "TOYOTA794 "); | ||
619 | if (type & DIBCOM52) | ||
620 | printk(KERN_CONT "DIBCOM52 "); | ||
621 | if (type & ZARLINK456) | ||
622 | printk(KERN_CONT "ZARLINK456 "); | ||
623 | if (type & CHINA) | ||
624 | printk(KERN_CONT "CHINA "); | ||
625 | if (type & F6MHZ) | ||
626 | printk(KERN_CONT "F6MHZ "); | ||
627 | if (type & INPUT2) | ||
628 | printk(KERN_CONT "INPUT2 "); | ||
629 | if (type & SCODE) | ||
630 | printk(KERN_CONT "SCODE "); | ||
631 | if (type & HAS_IF) | ||
632 | printk(KERN_CONT "HAS_IF_%d ", int_freq); | ||
633 | } | ||
634 | |||
635 | static int seek_firmware(struct dvb_frontend *fe, unsigned int type, | ||
636 | v4l2_std_id *id) | ||
637 | { | ||
638 | struct xc4000_priv *priv = fe->tuner_priv; | ||
639 | int i, best_i = -1; | ||
640 | unsigned int best_nr_diffs = 255U; | ||
641 | |||
642 | if (!priv->firm) { | ||
643 | printk(KERN_ERR "Error! firmware not loaded\n"); | ||
644 | return -EINVAL; | ||
645 | } | ||
646 | |||
647 | if (((type & ~SCODE) == 0) && (*id == 0)) | ||
648 | *id = V4L2_STD_PAL; | ||
649 | |||
650 | /* Seek for generic video standard match */ | ||
651 | for (i = 0; i < priv->firm_size; i++) { | ||
652 | v4l2_std_id id_diff_mask = | ||
653 | (priv->firm[i].id ^ (*id)) & (*id); | ||
654 | unsigned int type_diff_mask = | ||
655 | (priv->firm[i].type ^ type) | ||
656 | & (BASE_TYPES | DTV_TYPES | LCD | NOGD | MONO | SCODE); | ||
657 | unsigned int nr_diffs; | ||
658 | |||
659 | if (type_diff_mask | ||
660 | & (BASE | INIT1 | FM | DTV6 | DTV7 | DTV78 | DTV8 | SCODE)) | ||
661 | continue; | ||
662 | |||
663 | nr_diffs = hweight64(id_diff_mask) + hweight32(type_diff_mask); | ||
664 | if (!nr_diffs) /* Supports all the requested standards */ | ||
665 | goto found; | ||
666 | |||
667 | if (nr_diffs < best_nr_diffs) { | ||
668 | best_nr_diffs = nr_diffs; | ||
669 | best_i = i; | ||
670 | } | ||
671 | } | ||
672 | |||
673 | /* FIXME: Would make sense to seek for type "hint" match ? */ | ||
674 | if (best_i < 0) { | ||
675 | i = -ENOENT; | ||
676 | goto ret; | ||
677 | } | ||
678 | |||
679 | if (best_nr_diffs > 0U) { | ||
680 | printk(KERN_WARNING | ||
681 | "Selecting best matching firmware (%u bits differ) for " | ||
682 | "type=(%x), id %016llx:\n", | ||
683 | best_nr_diffs, type, (unsigned long long)*id); | ||
684 | i = best_i; | ||
685 | } | ||
686 | |||
687 | found: | ||
688 | *id = priv->firm[i].id; | ||
689 | |||
690 | ret: | ||
691 | if (debug) { | ||
692 | printk(KERN_DEBUG "%s firmware for type=", | ||
693 | (i < 0) ? "Can't find" : "Found"); | ||
694 | dump_firm_type(type); | ||
695 | printk(KERN_DEBUG "(%x), id %016llx.\n", type, (unsigned long long)*id); | ||
696 | } | ||
697 | return i; | ||
698 | } | ||
699 | |||
700 | static int load_firmware(struct dvb_frontend *fe, unsigned int type, | ||
701 | v4l2_std_id *id) | ||
702 | { | ||
703 | struct xc4000_priv *priv = fe->tuner_priv; | ||
704 | int pos, rc; | ||
705 | unsigned char *p; | ||
706 | |||
707 | pos = seek_firmware(fe, type, id); | ||
708 | if (pos < 0) | ||
709 | return pos; | ||
710 | |||
711 | p = priv->firm[pos].ptr; | ||
712 | |||
713 | /* Don't complain when the request fails because of i2c stretching */ | ||
714 | priv->ignore_i2c_write_errors = 1; | ||
715 | |||
716 | rc = xc_load_i2c_sequence(fe, p); | ||
717 | |||
718 | priv->ignore_i2c_write_errors = 0; | ||
719 | |||
720 | return rc; | ||
721 | } | ||
722 | |||
723 | static int xc4000_fwupload(struct dvb_frontend *fe) | ||
724 | { | ||
725 | struct xc4000_priv *priv = fe->tuner_priv; | ||
726 | const struct firmware *fw = NULL; | ||
727 | const unsigned char *p, *endp; | ||
728 | int rc = 0; | ||
729 | int n, n_array; | ||
730 | char name[33]; | ||
731 | const char *fname; | ||
732 | |||
733 | if (firmware_name[0] != '\0') | ||
734 | fname = firmware_name; | ||
735 | else | ||
736 | fname = XC4000_DEFAULT_FIRMWARE; | ||
737 | |||
738 | dprintk(1, "Reading firmware %s\n", fname); | ||
739 | rc = request_firmware(&fw, fname, priv->i2c_props.adap->dev.parent); | ||
740 | if (rc < 0) { | ||
741 | if (rc == -ENOENT) | ||
742 | printk(KERN_ERR "Error: firmware %s not found.\n", fname); | ||
743 | else | ||
744 | printk(KERN_ERR "Error %d while requesting firmware %s\n", | ||
745 | rc, fname); | ||
746 | |||
747 | return rc; | ||
748 | } | ||
749 | p = fw->data; | ||
750 | endp = p + fw->size; | ||
751 | |||
752 | if (fw->size < sizeof(name) - 1 + 2 + 2) { | ||
753 | printk(KERN_ERR "Error: firmware file %s has invalid size!\n", | ||
754 | fname); | ||
755 | goto corrupt; | ||
756 | } | ||
757 | |||
758 | memcpy(name, p, sizeof(name) - 1); | ||
759 | name[sizeof(name) - 1] = '\0'; | ||
760 | p += sizeof(name) - 1; | ||
761 | |||
762 | priv->firm_version = get_unaligned_le16(p); | ||
763 | p += 2; | ||
764 | |||
765 | n_array = get_unaligned_le16(p); | ||
766 | p += 2; | ||
767 | |||
768 | dprintk(1, "Loading %d firmware images from %s, type: %s, ver %d.%d\n", | ||
769 | n_array, fname, name, | ||
770 | priv->firm_version >> 8, priv->firm_version & 0xff); | ||
771 | |||
772 | priv->firm = kcalloc(n_array, sizeof(*priv->firm), GFP_KERNEL); | ||
773 | if (priv->firm == NULL) { | ||
774 | printk(KERN_ERR "Not enough memory to load firmware file.\n"); | ||
775 | rc = -ENOMEM; | ||
776 | goto done; | ||
777 | } | ||
778 | priv->firm_size = n_array; | ||
779 | |||
780 | n = -1; | ||
781 | while (p < endp) { | ||
782 | __u32 type, size; | ||
783 | v4l2_std_id id; | ||
784 | __u16 int_freq = 0; | ||
785 | |||
786 | n++; | ||
787 | if (n >= n_array) { | ||
788 | printk(KERN_ERR "More firmware images in file than " | ||
789 | "were expected!\n"); | ||
790 | goto corrupt; | ||
791 | } | ||
792 | |||
793 | /* Checks if there's enough bytes to read */ | ||
794 | if (endp - p < sizeof(type) + sizeof(id) + sizeof(size)) | ||
795 | goto header; | ||
796 | |||
797 | type = get_unaligned_le32(p); | ||
798 | p += sizeof(type); | ||
799 | |||
800 | id = get_unaligned_le64(p); | ||
801 | p += sizeof(id); | ||
802 | |||
803 | if (type & HAS_IF) { | ||
804 | int_freq = get_unaligned_le16(p); | ||
805 | p += sizeof(int_freq); | ||
806 | if (endp - p < sizeof(size)) | ||
807 | goto header; | ||
808 | } | ||
809 | |||
810 | size = get_unaligned_le32(p); | ||
811 | p += sizeof(size); | ||
812 | |||
813 | if (!size || size > endp - p) { | ||
814 | printk(KERN_ERR "Firmware type (%x), id %llx is corrupted (size=%d, expected %d)\n", | ||
815 | type, (unsigned long long)id, | ||
816 | (unsigned)(endp - p), size); | ||
817 | goto corrupt; | ||
818 | } | ||
819 | |||
820 | priv->firm[n].ptr = kzalloc(size, GFP_KERNEL); | ||
821 | if (priv->firm[n].ptr == NULL) { | ||
822 | printk(KERN_ERR "Not enough memory to load firmware file.\n"); | ||
823 | rc = -ENOMEM; | ||
824 | goto done; | ||
825 | } | ||
826 | |||
827 | if (debug) { | ||
828 | printk(KERN_DEBUG "Reading firmware type "); | ||
829 | dump_firm_type_and_int_freq(type, int_freq); | ||
830 | printk(KERN_DEBUG "(%x), id %llx, size=%d.\n", | ||
831 | type, (unsigned long long)id, size); | ||
832 | } | ||
833 | |||
834 | memcpy(priv->firm[n].ptr, p, size); | ||
835 | priv->firm[n].type = type; | ||
836 | priv->firm[n].id = id; | ||
837 | priv->firm[n].size = size; | ||
838 | priv->firm[n].int_freq = int_freq; | ||
839 | |||
840 | p += size; | ||
841 | } | ||
842 | |||
843 | if (n + 1 != priv->firm_size) { | ||
844 | printk(KERN_ERR "Firmware file is incomplete!\n"); | ||
845 | goto corrupt; | ||
846 | } | ||
847 | |||
848 | goto done; | ||
849 | |||
850 | header: | ||
851 | printk(KERN_ERR "Firmware header is incomplete!\n"); | ||
852 | corrupt: | ||
853 | rc = -EINVAL; | ||
854 | printk(KERN_ERR "Error: firmware file is corrupted!\n"); | ||
855 | |||
856 | done: | ||
857 | release_firmware(fw); | ||
858 | if (rc == 0) | ||
859 | dprintk(1, "Firmware files loaded.\n"); | ||
860 | |||
861 | return rc; | ||
862 | } | ||
863 | |||
864 | static int load_scode(struct dvb_frontend *fe, unsigned int type, | ||
865 | v4l2_std_id *id, __u16 int_freq, int scode) | ||
866 | { | ||
867 | struct xc4000_priv *priv = fe->tuner_priv; | ||
868 | int pos, rc; | ||
869 | unsigned char *p; | ||
870 | u8 scode_buf[13]; | ||
871 | u8 indirect_mode[5]; | ||
872 | |||
873 | dprintk(1, "%s called int_freq=%d\n", __func__, int_freq); | ||
874 | |||
875 | if (!int_freq) { | ||
876 | pos = seek_firmware(fe, type, id); | ||
877 | if (pos < 0) | ||
878 | return pos; | ||
879 | } else { | ||
880 | for (pos = 0; pos < priv->firm_size; pos++) { | ||
881 | if ((priv->firm[pos].int_freq == int_freq) && | ||
882 | (priv->firm[pos].type & HAS_IF)) | ||
883 | break; | ||
884 | } | ||
885 | if (pos == priv->firm_size) | ||
886 | return -ENOENT; | ||
887 | } | ||
888 | |||
889 | p = priv->firm[pos].ptr; | ||
890 | |||
891 | if (priv->firm[pos].size != 12 * 16 || scode >= 16) | ||
892 | return -EINVAL; | ||
893 | p += 12 * scode; | ||
894 | |||
895 | if (debug) { | ||
896 | tuner_info("Loading SCODE for type="); | ||
897 | dump_firm_type_and_int_freq(priv->firm[pos].type, | ||
898 | priv->firm[pos].int_freq); | ||
899 | printk(KERN_CONT "(%x), id %016llx.\n", priv->firm[pos].type, | ||
900 | (unsigned long long)*id); | ||
901 | } | ||
902 | |||
903 | scode_buf[0] = 0x00; | ||
904 | memcpy(&scode_buf[1], p, 12); | ||
905 | |||
906 | /* Enter direct-mode */ | ||
907 | rc = xc_write_reg(priv, XREG_DIRECTSITTING_MODE, 0); | ||
908 | if (rc < 0) { | ||
909 | printk(KERN_ERR "failed to put device into direct mode!\n"); | ||
910 | return -EIO; | ||
911 | } | ||
912 | |||
913 | rc = xc_send_i2c_data(priv, scode_buf, 13); | ||
914 | if (rc != 0) { | ||
915 | /* Even if the send failed, make sure we set back to indirect | ||
916 | mode */ | ||
917 | printk(KERN_ERR "Failed to set scode %d\n", rc); | ||
918 | } | ||
919 | |||
920 | /* Switch back to indirect-mode */ | ||
921 | memset(indirect_mode, 0, sizeof(indirect_mode)); | ||
922 | indirect_mode[4] = 0x88; | ||
923 | xc_send_i2c_data(priv, indirect_mode, sizeof(indirect_mode)); | ||
924 | msleep(10); | ||
925 | |||
926 | return 0; | ||
927 | } | ||
928 | |||
929 | static int check_firmware(struct dvb_frontend *fe, unsigned int type, | ||
930 | v4l2_std_id std, __u16 int_freq) | ||
931 | { | ||
932 | struct xc4000_priv *priv = fe->tuner_priv; | ||
933 | struct firmware_properties new_fw; | ||
934 | int rc = 0, is_retry = 0; | ||
935 | u16 hwmodel; | ||
936 | v4l2_std_id std0; | ||
937 | u8 hw_major, hw_minor, fw_major, fw_minor; | ||
938 | |||
939 | dprintk(1, "%s called\n", __func__); | ||
940 | |||
941 | if (!priv->firm) { | ||
942 | rc = xc4000_fwupload(fe); | ||
943 | if (rc < 0) | ||
944 | return rc; | ||
945 | } | ||
946 | |||
947 | retry: | ||
948 | new_fw.type = type; | ||
949 | new_fw.id = std; | ||
950 | new_fw.std_req = std; | ||
951 | new_fw.scode_table = SCODE; | ||
952 | new_fw.scode_nr = 0; | ||
953 | new_fw.int_freq = int_freq; | ||
954 | |||
955 | dprintk(1, "checking firmware, user requested type="); | ||
956 | if (debug) { | ||
957 | dump_firm_type(new_fw.type); | ||
958 | printk(KERN_CONT "(%x), id %016llx, ", new_fw.type, | ||
959 | (unsigned long long)new_fw.std_req); | ||
960 | if (!int_freq) | ||
961 | printk(KERN_CONT "scode_tbl "); | ||
962 | else | ||
963 | printk(KERN_CONT "int_freq %d, ", new_fw.int_freq); | ||
964 | printk(KERN_CONT "scode_nr %d\n", new_fw.scode_nr); | ||
965 | } | ||
966 | |||
967 | /* No need to reload base firmware if it matches */ | ||
968 | if (priv->cur_fw.type & BASE) { | ||
969 | dprintk(1, "BASE firmware not changed.\n"); | ||
970 | goto skip_base; | ||
971 | } | ||
972 | |||
973 | /* Updating BASE - forget about all currently loaded firmware */ | ||
974 | memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); | ||
975 | |||
976 | /* Reset is needed before loading firmware */ | ||
977 | rc = xc4000_tuner_reset(fe); | ||
978 | if (rc < 0) | ||
979 | goto fail; | ||
980 | |||
981 | /* BASE firmwares are all std0 */ | ||
982 | std0 = 0; | ||
983 | rc = load_firmware(fe, BASE, &std0); | ||
984 | if (rc < 0) { | ||
985 | printk(KERN_ERR "Error %d while loading base firmware\n", rc); | ||
986 | goto fail; | ||
987 | } | ||
988 | |||
989 | /* Load INIT1, if needed */ | ||
990 | dprintk(1, "Load init1 firmware, if exists\n"); | ||
991 | |||
992 | rc = load_firmware(fe, BASE | INIT1, &std0); | ||
993 | if (rc == -ENOENT) | ||
994 | rc = load_firmware(fe, BASE | INIT1, &std0); | ||
995 | if (rc < 0 && rc != -ENOENT) { | ||
996 | tuner_err("Error %d while loading init1 firmware\n", | ||
997 | rc); | ||
998 | goto fail; | ||
999 | } | ||
1000 | |||
1001 | skip_base: | ||
1002 | /* | ||
1003 | * No need to reload standard specific firmware if base firmware | ||
1004 | * was not reloaded and requested video standards have not changed. | ||
1005 | */ | ||
1006 | if (priv->cur_fw.type == (BASE | new_fw.type) && | ||
1007 | priv->cur_fw.std_req == std) { | ||
1008 | dprintk(1, "Std-specific firmware already loaded.\n"); | ||
1009 | goto skip_std_specific; | ||
1010 | } | ||
1011 | |||
1012 | /* Reloading std-specific firmware forces a SCODE update */ | ||
1013 | priv->cur_fw.scode_table = 0; | ||
1014 | |||
1015 | /* Load the standard firmware */ | ||
1016 | rc = load_firmware(fe, new_fw.type, &new_fw.id); | ||
1017 | |||
1018 | if (rc < 0) | ||
1019 | goto fail; | ||
1020 | |||
1021 | skip_std_specific: | ||
1022 | if (priv->cur_fw.scode_table == new_fw.scode_table && | ||
1023 | priv->cur_fw.scode_nr == new_fw.scode_nr) { | ||
1024 | dprintk(1, "SCODE firmware already loaded.\n"); | ||
1025 | goto check_device; | ||
1026 | } | ||
1027 | |||
1028 | /* Load SCODE firmware, if exists */ | ||
1029 | rc = load_scode(fe, new_fw.type | new_fw.scode_table, &new_fw.id, | ||
1030 | new_fw.int_freq, new_fw.scode_nr); | ||
1031 | if (rc != 0) | ||
1032 | dprintk(1, "load scode failed %d\n", rc); | ||
1033 | |||
1034 | check_device: | ||
1035 | rc = xc4000_readreg(priv, XREG_PRODUCT_ID, &hwmodel); | ||
1036 | |||
1037 | if (xc_get_version(priv, &hw_major, &hw_minor, &fw_major, | ||
1038 | &fw_minor) != 0) { | ||
1039 | printk(KERN_ERR "Unable to read tuner registers.\n"); | ||
1040 | goto fail; | ||
1041 | } | ||
1042 | |||
1043 | dprintk(1, "Device is Xceive %d version %d.%d, " | ||
1044 | "firmware version %d.%d\n", | ||
1045 | hwmodel, hw_major, hw_minor, fw_major, fw_minor); | ||
1046 | |||
1047 | /* Check firmware version against what we downloaded. */ | ||
1048 | if (priv->firm_version != ((fw_major << 8) | fw_minor)) { | ||
1049 | printk(KERN_WARNING | ||
1050 | "Incorrect readback of firmware version %d.%d.\n", | ||
1051 | fw_major, fw_minor); | ||
1052 | goto fail; | ||
1053 | } | ||
1054 | |||
1055 | /* Check that the tuner hardware model remains consistent over time. */ | ||
1056 | if (priv->hwmodel == 0 && | ||
1057 | (hwmodel == XC_PRODUCT_ID_XC4000 || | ||
1058 | hwmodel == XC_PRODUCT_ID_XC4100)) { | ||
1059 | priv->hwmodel = hwmodel; | ||
1060 | priv->hwvers = (hw_major << 8) | hw_minor; | ||
1061 | } else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel || | ||
1062 | priv->hwvers != ((hw_major << 8) | hw_minor)) { | ||
1063 | printk(KERN_WARNING | ||
1064 | "Read invalid device hardware information - tuner " | ||
1065 | "hung?\n"); | ||
1066 | goto fail; | ||
1067 | } | ||
1068 | |||
1069 | memcpy(&priv->cur_fw, &new_fw, sizeof(priv->cur_fw)); | ||
1070 | |||
1071 | /* | ||
1072 | * By setting BASE in cur_fw.type only after successfully loading all | ||
1073 | * firmwares, we can: | ||
1074 | * 1. Identify that BASE firmware with type=0 has been loaded; | ||
1075 | * 2. Tell whether BASE firmware was just changed the next time through. | ||
1076 | */ | ||
1077 | priv->cur_fw.type |= BASE; | ||
1078 | |||
1079 | return 0; | ||
1080 | |||
1081 | fail: | ||
1082 | memset(&priv->cur_fw, 0, sizeof(priv->cur_fw)); | ||
1083 | if (!is_retry) { | ||
1084 | msleep(50); | ||
1085 | is_retry = 1; | ||
1086 | dprintk(1, "Retrying firmware load\n"); | ||
1087 | goto retry; | ||
1088 | } | ||
1089 | |||
1090 | if (rc == -ENOENT) | ||
1091 | rc = -EINVAL; | ||
1092 | return rc; | ||
1093 | } | ||
1094 | |||
1095 | static void xc_debug_dump(struct xc4000_priv *priv) | ||
1096 | { | ||
1097 | u16 adc_envelope; | ||
1098 | u32 freq_error_hz = 0; | ||
1099 | u16 lock_status; | ||
1100 | u32 hsync_freq_hz = 0; | ||
1101 | u16 frame_lines; | ||
1102 | u16 quality; | ||
1103 | u16 signal = 0; | ||
1104 | u16 noise = 0; | ||
1105 | u8 hw_majorversion = 0, hw_minorversion = 0; | ||
1106 | u8 fw_majorversion = 0, fw_minorversion = 0; | ||
1107 | |||
1108 | xc_get_adc_envelope(priv, &adc_envelope); | ||
1109 | dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope); | ||
1110 | |||
1111 | xc_get_frequency_error(priv, &freq_error_hz); | ||
1112 | dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz); | ||
1113 | |||
1114 | xc_get_lock_status(priv, &lock_status); | ||
1115 | dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n", | ||
1116 | lock_status); | ||
1117 | |||
1118 | xc_get_version(priv, &hw_majorversion, &hw_minorversion, | ||
1119 | &fw_majorversion, &fw_minorversion); | ||
1120 | dprintk(1, "*** HW: V%02x.%02x, FW: V%02x.%02x\n", | ||
1121 | hw_majorversion, hw_minorversion, | ||
1122 | fw_majorversion, fw_minorversion); | ||
1123 | |||
1124 | if (priv->video_standard < XC4000_DTV6) { | ||
1125 | xc_get_hsync_freq(priv, &hsync_freq_hz); | ||
1126 | dprintk(1, "*** Horizontal sync frequency = %d Hz\n", | ||
1127 | hsync_freq_hz); | ||
1128 | |||
1129 | xc_get_frame_lines(priv, &frame_lines); | ||
1130 | dprintk(1, "*** Frame lines = %d\n", frame_lines); | ||
1131 | } | ||
1132 | |||
1133 | xc_get_quality(priv, &quality); | ||
1134 | dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality); | ||
1135 | |||
1136 | xc_get_signal_level(priv, &signal); | ||
1137 | dprintk(1, "*** Signal level = -%ddB (%d)\n", signal >> 8, signal); | ||
1138 | |||
1139 | xc_get_noise_level(priv, &noise); | ||
1140 | dprintk(1, "*** Noise level = %ddB (%d)\n", noise >> 8, noise); | ||
1141 | } | ||
1142 | |||
1143 | static int xc4000_set_params(struct dvb_frontend *fe) | ||
1144 | { | ||
1145 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
1146 | u32 delsys = c->delivery_system; | ||
1147 | u32 bw = c->bandwidth_hz; | ||
1148 | struct xc4000_priv *priv = fe->tuner_priv; | ||
1149 | unsigned int type; | ||
1150 | int ret = -EREMOTEIO; | ||
1151 | |||
1152 | dprintk(1, "%s() frequency=%d (Hz)\n", __func__, c->frequency); | ||
1153 | |||
1154 | mutex_lock(&priv->lock); | ||
1155 | |||
1156 | switch (delsys) { | ||
1157 | case SYS_ATSC: | ||
1158 | dprintk(1, "%s() VSB modulation\n", __func__); | ||
1159 | priv->rf_mode = XC_RF_MODE_AIR; | ||
1160 | priv->freq_hz = c->frequency - 1750000; | ||
1161 | priv->video_standard = XC4000_DTV6; | ||
1162 | type = DTV6; | ||
1163 | break; | ||
1164 | case SYS_DVBC_ANNEX_B: | ||
1165 | dprintk(1, "%s() QAM modulation\n", __func__); | ||
1166 | priv->rf_mode = XC_RF_MODE_CABLE; | ||
1167 | priv->freq_hz = c->frequency - 1750000; | ||
1168 | priv->video_standard = XC4000_DTV6; | ||
1169 | type = DTV6; | ||
1170 | break; | ||
1171 | case SYS_DVBT: | ||
1172 | case SYS_DVBT2: | ||
1173 | dprintk(1, "%s() OFDM\n", __func__); | ||
1174 | if (bw == 0) { | ||
1175 | if (c->frequency < 400000000) { | ||
1176 | priv->freq_hz = c->frequency - 2250000; | ||
1177 | } else { | ||
1178 | priv->freq_hz = c->frequency - 2750000; | ||
1179 | } | ||
1180 | priv->video_standard = XC4000_DTV7_8; | ||
1181 | type = DTV78; | ||
1182 | } else if (bw <= 6000000) { | ||
1183 | priv->video_standard = XC4000_DTV6; | ||
1184 | priv->freq_hz = c->frequency - 1750000; | ||
1185 | type = DTV6; | ||
1186 | } else if (bw <= 7000000) { | ||
1187 | priv->video_standard = XC4000_DTV7; | ||
1188 | priv->freq_hz = c->frequency - 2250000; | ||
1189 | type = DTV7; | ||
1190 | } else { | ||
1191 | priv->video_standard = XC4000_DTV8; | ||
1192 | priv->freq_hz = c->frequency - 2750000; | ||
1193 | type = DTV8; | ||
1194 | } | ||
1195 | priv->rf_mode = XC_RF_MODE_AIR; | ||
1196 | break; | ||
1197 | default: | ||
1198 | printk(KERN_ERR "xc4000 delivery system not supported!\n"); | ||
1199 | ret = -EINVAL; | ||
1200 | goto fail; | ||
1201 | } | ||
1202 | |||
1203 | dprintk(1, "%s() frequency=%d (compensated)\n", | ||
1204 | __func__, priv->freq_hz); | ||
1205 | |||
1206 | /* Make sure the correct firmware type is loaded */ | ||
1207 | if (check_firmware(fe, type, 0, priv->if_khz) != 0) | ||
1208 | goto fail; | ||
1209 | |||
1210 | priv->bandwidth = c->bandwidth_hz; | ||
1211 | |||
1212 | ret = xc_set_signal_source(priv, priv->rf_mode); | ||
1213 | if (ret != 0) { | ||
1214 | printk(KERN_ERR "xc4000: xc_set_signal_source(%d) failed\n", | ||
1215 | priv->rf_mode); | ||
1216 | goto fail; | ||
1217 | } else { | ||
1218 | u16 video_mode, audio_mode; | ||
1219 | video_mode = xc4000_standard[priv->video_standard].video_mode; | ||
1220 | audio_mode = xc4000_standard[priv->video_standard].audio_mode; | ||
1221 | if (type == DTV6 && priv->firm_version != 0x0102) | ||
1222 | video_mode |= 0x0001; | ||
1223 | ret = xc_set_tv_standard(priv, video_mode, audio_mode); | ||
1224 | if (ret != 0) { | ||
1225 | printk(KERN_ERR "xc4000: xc_set_tv_standard failed\n"); | ||
1226 | /* DJH - do not return when it fails... */ | ||
1227 | /* goto fail; */ | ||
1228 | } | ||
1229 | } | ||
1230 | |||
1231 | if (xc_write_reg(priv, XREG_D_CODE, 0) == 0) | ||
1232 | ret = 0; | ||
1233 | if (priv->dvb_amplitude != 0) { | ||
1234 | if (xc_write_reg(priv, XREG_AMPLITUDE, | ||
1235 | (priv->firm_version != 0x0102 || | ||
1236 | priv->dvb_amplitude != 134 ? | ||
1237 | priv->dvb_amplitude : 132)) != 0) | ||
1238 | ret = -EREMOTEIO; | ||
1239 | } | ||
1240 | if (priv->set_smoothedcvbs != 0) { | ||
1241 | if (xc_write_reg(priv, XREG_SMOOTHEDCVBS, 1) != 0) | ||
1242 | ret = -EREMOTEIO; | ||
1243 | } | ||
1244 | if (ret != 0) { | ||
1245 | printk(KERN_ERR "xc4000: setting registers failed\n"); | ||
1246 | /* goto fail; */ | ||
1247 | } | ||
1248 | |||
1249 | xc_tune_channel(priv, priv->freq_hz); | ||
1250 | |||
1251 | ret = 0; | ||
1252 | |||
1253 | fail: | ||
1254 | mutex_unlock(&priv->lock); | ||
1255 | |||
1256 | return ret; | ||
1257 | } | ||
1258 | |||
1259 | static int xc4000_set_analog_params(struct dvb_frontend *fe, | ||
1260 | struct analog_parameters *params) | ||
1261 | { | ||
1262 | struct xc4000_priv *priv = fe->tuner_priv; | ||
1263 | unsigned int type = 0; | ||
1264 | int ret = -EREMOTEIO; | ||
1265 | |||
1266 | if (params->mode == V4L2_TUNER_RADIO) { | ||
1267 | dprintk(1, "%s() frequency=%d (in units of 62.5Hz)\n", | ||
1268 | __func__, params->frequency); | ||
1269 | |||
1270 | mutex_lock(&priv->lock); | ||
1271 | |||
1272 | params->std = 0; | ||
1273 | priv->freq_hz = params->frequency * 125L / 2; | ||
1274 | |||
1275 | if (audio_std & XC4000_AUDIO_STD_INPUT1) { | ||
1276 | priv->video_standard = XC4000_FM_Radio_INPUT1; | ||
1277 | type = FM | INPUT1; | ||
1278 | } else { | ||
1279 | priv->video_standard = XC4000_FM_Radio_INPUT2; | ||
1280 | type = FM | INPUT2; | ||
1281 | } | ||
1282 | |||
1283 | goto tune_channel; | ||
1284 | } | ||
1285 | |||
1286 | dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n", | ||
1287 | __func__, params->frequency); | ||
1288 | |||
1289 | mutex_lock(&priv->lock); | ||
1290 | |||
1291 | /* params->frequency is in units of 62.5khz */ | ||
1292 | priv->freq_hz = params->frequency * 62500; | ||
1293 | |||
1294 | params->std &= V4L2_STD_ALL; | ||
1295 | /* if std is not defined, choose one */ | ||
1296 | if (!params->std) | ||
1297 | params->std = V4L2_STD_PAL_BG; | ||
1298 | |||
1299 | if (audio_std & XC4000_AUDIO_STD_MONO) | ||
1300 | type = MONO; | ||
1301 | |||
1302 | if (params->std & V4L2_STD_MN) { | ||
1303 | params->std = V4L2_STD_MN; | ||
1304 | if (audio_std & XC4000_AUDIO_STD_MONO) { | ||
1305 | priv->video_standard = XC4000_MN_NTSC_PAL_Mono; | ||
1306 | } else if (audio_std & XC4000_AUDIO_STD_A2) { | ||
1307 | params->std |= V4L2_STD_A2; | ||
1308 | priv->video_standard = XC4000_MN_NTSC_PAL_A2; | ||
1309 | } else { | ||
1310 | params->std |= V4L2_STD_BTSC; | ||
1311 | priv->video_standard = XC4000_MN_NTSC_PAL_BTSC; | ||
1312 | } | ||
1313 | goto tune_channel; | ||
1314 | } | ||
1315 | |||
1316 | if (params->std & V4L2_STD_PAL_BG) { | ||
1317 | params->std = V4L2_STD_PAL_BG; | ||
1318 | if (audio_std & XC4000_AUDIO_STD_MONO) { | ||
1319 | priv->video_standard = XC4000_BG_PAL_MONO; | ||
1320 | } else if (!(audio_std & XC4000_AUDIO_STD_A2)) { | ||
1321 | if (!(audio_std & XC4000_AUDIO_STD_B)) { | ||
1322 | params->std |= V4L2_STD_NICAM_A; | ||
1323 | priv->video_standard = XC4000_BG_PAL_NICAM; | ||
1324 | } else { | ||
1325 | params->std |= V4L2_STD_NICAM_B; | ||
1326 | priv->video_standard = XC4000_BG_PAL_NICAM; | ||
1327 | } | ||
1328 | } else { | ||
1329 | if (!(audio_std & XC4000_AUDIO_STD_B)) { | ||
1330 | params->std |= V4L2_STD_A2_A; | ||
1331 | priv->video_standard = XC4000_BG_PAL_A2; | ||
1332 | } else { | ||
1333 | params->std |= V4L2_STD_A2_B; | ||
1334 | priv->video_standard = XC4000_BG_PAL_A2; | ||
1335 | } | ||
1336 | } | ||
1337 | goto tune_channel; | ||
1338 | } | ||
1339 | |||
1340 | if (params->std & V4L2_STD_PAL_I) { | ||
1341 | /* default to NICAM audio standard */ | ||
1342 | params->std = V4L2_STD_PAL_I | V4L2_STD_NICAM; | ||
1343 | if (audio_std & XC4000_AUDIO_STD_MONO) | ||
1344 | priv->video_standard = XC4000_I_PAL_NICAM_MONO; | ||
1345 | else | ||
1346 | priv->video_standard = XC4000_I_PAL_NICAM; | ||
1347 | goto tune_channel; | ||
1348 | } | ||
1349 | |||
1350 | if (params->std & V4L2_STD_PAL_DK) { | ||
1351 | params->std = V4L2_STD_PAL_DK; | ||
1352 | if (audio_std & XC4000_AUDIO_STD_MONO) { | ||
1353 | priv->video_standard = XC4000_DK_PAL_MONO; | ||
1354 | } else if (audio_std & XC4000_AUDIO_STD_A2) { | ||
1355 | params->std |= V4L2_STD_A2; | ||
1356 | priv->video_standard = XC4000_DK_PAL_A2; | ||
1357 | } else { | ||
1358 | params->std |= V4L2_STD_NICAM; | ||
1359 | priv->video_standard = XC4000_DK_PAL_NICAM; | ||
1360 | } | ||
1361 | goto tune_channel; | ||
1362 | } | ||
1363 | |||
1364 | if (params->std & V4L2_STD_SECAM_DK) { | ||
1365 | /* default to A2 audio standard */ | ||
1366 | params->std = V4L2_STD_SECAM_DK | V4L2_STD_A2; | ||
1367 | if (audio_std & XC4000_AUDIO_STD_L) { | ||
1368 | type = 0; | ||
1369 | priv->video_standard = XC4000_DK_SECAM_NICAM; | ||
1370 | } else if (audio_std & XC4000_AUDIO_STD_MONO) { | ||
1371 | priv->video_standard = XC4000_DK_SECAM_A2MONO; | ||
1372 | } else if (audio_std & XC4000_AUDIO_STD_K3) { | ||
1373 | params->std |= V4L2_STD_SECAM_K3; | ||
1374 | priv->video_standard = XC4000_DK_SECAM_A2LDK3; | ||
1375 | } else { | ||
1376 | priv->video_standard = XC4000_DK_SECAM_A2DK1; | ||
1377 | } | ||
1378 | goto tune_channel; | ||
1379 | } | ||
1380 | |||
1381 | if (params->std & V4L2_STD_SECAM_L) { | ||
1382 | /* default to NICAM audio standard */ | ||
1383 | type = 0; | ||
1384 | params->std = V4L2_STD_SECAM_L | V4L2_STD_NICAM; | ||
1385 | priv->video_standard = XC4000_L_SECAM_NICAM; | ||
1386 | goto tune_channel; | ||
1387 | } | ||
1388 | |||
1389 | if (params->std & V4L2_STD_SECAM_LC) { | ||
1390 | /* default to NICAM audio standard */ | ||
1391 | type = 0; | ||
1392 | params->std = V4L2_STD_SECAM_LC | V4L2_STD_NICAM; | ||
1393 | priv->video_standard = XC4000_LC_SECAM_NICAM; | ||
1394 | goto tune_channel; | ||
1395 | } | ||
1396 | |||
1397 | tune_channel: | ||
1398 | /* FIXME: it could be air. */ | ||
1399 | priv->rf_mode = XC_RF_MODE_CABLE; | ||
1400 | |||
1401 | if (check_firmware(fe, type, params->std, | ||
1402 | xc4000_standard[priv->video_standard].int_freq) != 0) | ||
1403 | goto fail; | ||
1404 | |||
1405 | ret = xc_set_signal_source(priv, priv->rf_mode); | ||
1406 | if (ret != 0) { | ||
1407 | printk(KERN_ERR | ||
1408 | "xc4000: xc_set_signal_source(%d) failed\n", | ||
1409 | priv->rf_mode); | ||
1410 | goto fail; | ||
1411 | } else { | ||
1412 | u16 video_mode, audio_mode; | ||
1413 | video_mode = xc4000_standard[priv->video_standard].video_mode; | ||
1414 | audio_mode = xc4000_standard[priv->video_standard].audio_mode; | ||
1415 | if (priv->video_standard < XC4000_BG_PAL_A2) { | ||
1416 | if (type & NOGD) | ||
1417 | video_mode &= 0xFF7F; | ||
1418 | } else if (priv->video_standard < XC4000_I_PAL_NICAM) { | ||
1419 | if (priv->firm_version == 0x0102) | ||
1420 | video_mode &= 0xFEFF; | ||
1421 | if (audio_std & XC4000_AUDIO_STD_B) | ||
1422 | video_mode |= 0x0080; | ||
1423 | } | ||
1424 | ret = xc_set_tv_standard(priv, video_mode, audio_mode); | ||
1425 | if (ret != 0) { | ||
1426 | printk(KERN_ERR "xc4000: xc_set_tv_standard failed\n"); | ||
1427 | goto fail; | ||
1428 | } | ||
1429 | } | ||
1430 | |||
1431 | if (xc_write_reg(priv, XREG_D_CODE, 0) == 0) | ||
1432 | ret = 0; | ||
1433 | if (xc_write_reg(priv, XREG_AMPLITUDE, 1) != 0) | ||
1434 | ret = -EREMOTEIO; | ||
1435 | if (priv->set_smoothedcvbs != 0) { | ||
1436 | if (xc_write_reg(priv, XREG_SMOOTHEDCVBS, 1) != 0) | ||
1437 | ret = -EREMOTEIO; | ||
1438 | } | ||
1439 | if (ret != 0) { | ||
1440 | printk(KERN_ERR "xc4000: setting registers failed\n"); | ||
1441 | goto fail; | ||
1442 | } | ||
1443 | |||
1444 | xc_tune_channel(priv, priv->freq_hz); | ||
1445 | |||
1446 | ret = 0; | ||
1447 | |||
1448 | fail: | ||
1449 | mutex_unlock(&priv->lock); | ||
1450 | |||
1451 | return ret; | ||
1452 | } | ||
1453 | |||
1454 | static int xc4000_get_signal(struct dvb_frontend *fe, u16 *strength) | ||
1455 | { | ||
1456 | struct xc4000_priv *priv = fe->tuner_priv; | ||
1457 | u16 value = 0; | ||
1458 | int rc; | ||
1459 | |||
1460 | mutex_lock(&priv->lock); | ||
1461 | rc = xc4000_readreg(priv, XREG_SIGNAL_LEVEL, &value); | ||
1462 | mutex_unlock(&priv->lock); | ||
1463 | |||
1464 | if (rc < 0) | ||
1465 | goto ret; | ||
1466 | |||
1467 | /* Informations from real testing of DVB-T and radio part, | ||
1468 | coeficient for one dB is 0xff. | ||
1469 | */ | ||
1470 | tuner_dbg("Signal strength: -%ddB (%05d)\n", value >> 8, value); | ||
1471 | |||
1472 | /* all known digital modes */ | ||
1473 | if ((priv->video_standard == XC4000_DTV6) || | ||
1474 | (priv->video_standard == XC4000_DTV7) || | ||
1475 | (priv->video_standard == XC4000_DTV7_8) || | ||
1476 | (priv->video_standard == XC4000_DTV8)) | ||
1477 | goto digital; | ||
1478 | |||
1479 | /* Analog mode has NOISE LEVEL important, signal | ||
1480 | depends only on gain of antenna and amplifiers, | ||
1481 | but it doesn't tell anything about real quality | ||
1482 | of reception. | ||
1483 | */ | ||
1484 | mutex_lock(&priv->lock); | ||
1485 | rc = xc4000_readreg(priv, XREG_NOISE_LEVEL, &value); | ||
1486 | mutex_unlock(&priv->lock); | ||
1487 | |||
1488 | tuner_dbg("Noise level: %ddB (%05d)\n", value >> 8, value); | ||
1489 | |||
1490 | /* highest noise level: 32dB */ | ||
1491 | if (value >= 0x2000) { | ||
1492 | value = 0; | ||
1493 | } else { | ||
1494 | value = ~value << 3; | ||
1495 | } | ||
1496 | |||
1497 | goto ret; | ||
1498 | |||
1499 | /* Digital mode has SIGNAL LEVEL important and real | ||
1500 | noise level is stored in demodulator registers. | ||
1501 | */ | ||
1502 | digital: | ||
1503 | /* best signal: -50dB */ | ||
1504 | if (value <= 0x3200) { | ||
1505 | value = 0xffff; | ||
1506 | /* minimum: -114dB - should be 0x7200 but real zero is 0x713A */ | ||
1507 | } else if (value >= 0x713A) { | ||
1508 | value = 0; | ||
1509 | } else { | ||
1510 | value = ~(value - 0x3200) << 2; | ||
1511 | } | ||
1512 | |||
1513 | ret: | ||
1514 | *strength = value; | ||
1515 | |||
1516 | return rc; | ||
1517 | } | ||
1518 | |||
1519 | static int xc4000_get_frequency(struct dvb_frontend *fe, u32 *freq) | ||
1520 | { | ||
1521 | struct xc4000_priv *priv = fe->tuner_priv; | ||
1522 | |||
1523 | *freq = priv->freq_hz; | ||
1524 | |||
1525 | if (debug) { | ||
1526 | mutex_lock(&priv->lock); | ||
1527 | if ((priv->cur_fw.type | ||
1528 | & (BASE | FM | DTV6 | DTV7 | DTV78 | DTV8)) == BASE) { | ||
1529 | u16 snr = 0; | ||
1530 | if (xc4000_readreg(priv, XREG_SNR, &snr) == 0) { | ||
1531 | mutex_unlock(&priv->lock); | ||
1532 | dprintk(1, "%s() freq = %u, SNR = %d\n", | ||
1533 | __func__, *freq, snr); | ||
1534 | return 0; | ||
1535 | } | ||
1536 | } | ||
1537 | mutex_unlock(&priv->lock); | ||
1538 | } | ||
1539 | |||
1540 | dprintk(1, "%s()\n", __func__); | ||
1541 | |||
1542 | return 0; | ||
1543 | } | ||
1544 | |||
1545 | static int xc4000_get_bandwidth(struct dvb_frontend *fe, u32 *bw) | ||
1546 | { | ||
1547 | struct xc4000_priv *priv = fe->tuner_priv; | ||
1548 | dprintk(1, "%s()\n", __func__); | ||
1549 | |||
1550 | *bw = priv->bandwidth; | ||
1551 | return 0; | ||
1552 | } | ||
1553 | |||
1554 | static int xc4000_get_status(struct dvb_frontend *fe, u32 *status) | ||
1555 | { | ||
1556 | struct xc4000_priv *priv = fe->tuner_priv; | ||
1557 | u16 lock_status = 0; | ||
1558 | |||
1559 | mutex_lock(&priv->lock); | ||
1560 | |||
1561 | if (priv->cur_fw.type & BASE) | ||
1562 | xc_get_lock_status(priv, &lock_status); | ||
1563 | |||
1564 | *status = (lock_status == 1 ? | ||
1565 | TUNER_STATUS_LOCKED | TUNER_STATUS_STEREO : 0); | ||
1566 | if (priv->cur_fw.type & (DTV6 | DTV7 | DTV78 | DTV8)) | ||
1567 | *status &= (~TUNER_STATUS_STEREO); | ||
1568 | |||
1569 | mutex_unlock(&priv->lock); | ||
1570 | |||
1571 | dprintk(2, "%s() lock_status = %d\n", __func__, lock_status); | ||
1572 | |||
1573 | return 0; | ||
1574 | } | ||
1575 | |||
1576 | static int xc4000_sleep(struct dvb_frontend *fe) | ||
1577 | { | ||
1578 | struct xc4000_priv *priv = fe->tuner_priv; | ||
1579 | int ret = 0; | ||
1580 | |||
1581 | dprintk(1, "%s()\n", __func__); | ||
1582 | |||
1583 | mutex_lock(&priv->lock); | ||
1584 | |||
1585 | /* Avoid firmware reload on slow devices */ | ||
1586 | if ((no_poweroff == 2 || | ||
1587 | (no_poweroff == 0 && priv->default_pm != 0)) && | ||
1588 | (priv->cur_fw.type & BASE) != 0) { | ||
1589 | /* force reset and firmware reload */ | ||
1590 | priv->cur_fw.type = XC_POWERED_DOWN; | ||
1591 | |||
1592 | if (xc_write_reg(priv, XREG_POWER_DOWN, 0) != 0) { | ||
1593 | printk(KERN_ERR | ||
1594 | "xc4000: %s() unable to shutdown tuner\n", | ||
1595 | __func__); | ||
1596 | ret = -EREMOTEIO; | ||
1597 | } | ||
1598 | msleep(20); | ||
1599 | } | ||
1600 | |||
1601 | mutex_unlock(&priv->lock); | ||
1602 | |||
1603 | return ret; | ||
1604 | } | ||
1605 | |||
1606 | static int xc4000_init(struct dvb_frontend *fe) | ||
1607 | { | ||
1608 | dprintk(1, "%s()\n", __func__); | ||
1609 | |||
1610 | return 0; | ||
1611 | } | ||
1612 | |||
1613 | static int xc4000_release(struct dvb_frontend *fe) | ||
1614 | { | ||
1615 | struct xc4000_priv *priv = fe->tuner_priv; | ||
1616 | |||
1617 | dprintk(1, "%s()\n", __func__); | ||
1618 | |||
1619 | mutex_lock(&xc4000_list_mutex); | ||
1620 | |||
1621 | if (priv) | ||
1622 | hybrid_tuner_release_state(priv); | ||
1623 | |||
1624 | mutex_unlock(&xc4000_list_mutex); | ||
1625 | |||
1626 | fe->tuner_priv = NULL; | ||
1627 | |||
1628 | return 0; | ||
1629 | } | ||
1630 | |||
1631 | static const struct dvb_tuner_ops xc4000_tuner_ops = { | ||
1632 | .info = { | ||
1633 | .name = "Xceive XC4000", | ||
1634 | .frequency_min = 1000000, | ||
1635 | .frequency_max = 1023000000, | ||
1636 | .frequency_step = 50000, | ||
1637 | }, | ||
1638 | |||
1639 | .release = xc4000_release, | ||
1640 | .init = xc4000_init, | ||
1641 | .sleep = xc4000_sleep, | ||
1642 | |||
1643 | .set_params = xc4000_set_params, | ||
1644 | .set_analog_params = xc4000_set_analog_params, | ||
1645 | .get_frequency = xc4000_get_frequency, | ||
1646 | .get_rf_strength = xc4000_get_signal, | ||
1647 | .get_bandwidth = xc4000_get_bandwidth, | ||
1648 | .get_status = xc4000_get_status | ||
1649 | }; | ||
1650 | |||
1651 | struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe, | ||
1652 | struct i2c_adapter *i2c, | ||
1653 | struct xc4000_config *cfg) | ||
1654 | { | ||
1655 | struct xc4000_priv *priv = NULL; | ||
1656 | int instance; | ||
1657 | u16 id = 0; | ||
1658 | |||
1659 | dprintk(1, "%s(%d-%04x)\n", __func__, | ||
1660 | i2c ? i2c_adapter_id(i2c) : -1, | ||
1661 | cfg ? cfg->i2c_address : -1); | ||
1662 | |||
1663 | mutex_lock(&xc4000_list_mutex); | ||
1664 | |||
1665 | instance = hybrid_tuner_request_state(struct xc4000_priv, priv, | ||
1666 | hybrid_tuner_instance_list, | ||
1667 | i2c, cfg->i2c_address, "xc4000"); | ||
1668 | switch (instance) { | ||
1669 | case 0: | ||
1670 | goto fail; | ||
1671 | break; | ||
1672 | case 1: | ||
1673 | /* new tuner instance */ | ||
1674 | priv->bandwidth = 6000000; | ||
1675 | /* set default configuration */ | ||
1676 | priv->if_khz = 4560; | ||
1677 | priv->default_pm = 0; | ||
1678 | priv->dvb_amplitude = 134; | ||
1679 | priv->set_smoothedcvbs = 1; | ||
1680 | mutex_init(&priv->lock); | ||
1681 | fe->tuner_priv = priv; | ||
1682 | break; | ||
1683 | default: | ||
1684 | /* existing tuner instance */ | ||
1685 | fe->tuner_priv = priv; | ||
1686 | break; | ||
1687 | } | ||
1688 | |||
1689 | if (cfg->if_khz != 0) { | ||
1690 | /* copy configuration if provided by the caller */ | ||
1691 | priv->if_khz = cfg->if_khz; | ||
1692 | priv->default_pm = cfg->default_pm; | ||
1693 | priv->dvb_amplitude = cfg->dvb_amplitude; | ||
1694 | priv->set_smoothedcvbs = cfg->set_smoothedcvbs; | ||
1695 | } | ||
1696 | |||
1697 | /* Check if firmware has been loaded. It is possible that another | ||
1698 | instance of the driver has loaded the firmware. | ||
1699 | */ | ||
1700 | |||
1701 | if (instance == 1) { | ||
1702 | if (xc4000_readreg(priv, XREG_PRODUCT_ID, &id) != 0) | ||
1703 | goto fail; | ||
1704 | } else { | ||
1705 | id = ((priv->cur_fw.type & BASE) != 0 ? | ||
1706 | priv->hwmodel : XC_PRODUCT_ID_FW_NOT_LOADED); | ||
1707 | } | ||
1708 | |||
1709 | switch (id) { | ||
1710 | case XC_PRODUCT_ID_XC4000: | ||
1711 | case XC_PRODUCT_ID_XC4100: | ||
1712 | printk(KERN_INFO | ||
1713 | "xc4000: Successfully identified at address 0x%02x\n", | ||
1714 | cfg->i2c_address); | ||
1715 | printk(KERN_INFO | ||
1716 | "xc4000: Firmware has been loaded previously\n"); | ||
1717 | break; | ||
1718 | case XC_PRODUCT_ID_FW_NOT_LOADED: | ||
1719 | printk(KERN_INFO | ||
1720 | "xc4000: Successfully identified at address 0x%02x\n", | ||
1721 | cfg->i2c_address); | ||
1722 | printk(KERN_INFO | ||
1723 | "xc4000: Firmware has not been loaded previously\n"); | ||
1724 | break; | ||
1725 | default: | ||
1726 | printk(KERN_ERR | ||
1727 | "xc4000: Device not found at addr 0x%02x (0x%x)\n", | ||
1728 | cfg->i2c_address, id); | ||
1729 | goto fail; | ||
1730 | } | ||
1731 | |||
1732 | mutex_unlock(&xc4000_list_mutex); | ||
1733 | |||
1734 | memcpy(&fe->ops.tuner_ops, &xc4000_tuner_ops, | ||
1735 | sizeof(struct dvb_tuner_ops)); | ||
1736 | |||
1737 | if (instance == 1) { | ||
1738 | int ret; | ||
1739 | mutex_lock(&priv->lock); | ||
1740 | ret = xc4000_fwupload(fe); | ||
1741 | mutex_unlock(&priv->lock); | ||
1742 | if (ret != 0) | ||
1743 | goto fail2; | ||
1744 | } | ||
1745 | |||
1746 | return fe; | ||
1747 | fail: | ||
1748 | mutex_unlock(&xc4000_list_mutex); | ||
1749 | fail2: | ||
1750 | xc4000_release(fe); | ||
1751 | return NULL; | ||
1752 | } | ||
1753 | EXPORT_SYMBOL(xc4000_attach); | ||
1754 | |||
1755 | MODULE_AUTHOR("Steven Toth, Davide Ferri"); | ||
1756 | MODULE_DESCRIPTION("Xceive xc4000 silicon tuner driver"); | ||
1757 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/tuners/xc4000.h b/drivers/media/tuners/xc4000.h new file mode 100644 index 000000000000..e6a44d151cbd --- /dev/null +++ b/drivers/media/tuners/xc4000.h | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * Driver for Xceive XC4000 "QAM/8VSB single chip tuner" | ||
3 | * | ||
4 | * Copyright (c) 2007 Steven Toth <stoth@linuxtv.org> | ||
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 __XC4000_H__ | ||
23 | #define __XC4000_H__ | ||
24 | |||
25 | #include <linux/firmware.h> | ||
26 | |||
27 | struct dvb_frontend; | ||
28 | struct i2c_adapter; | ||
29 | |||
30 | struct xc4000_config { | ||
31 | u8 i2c_address; | ||
32 | /* if non-zero, power management is enabled by default */ | ||
33 | u8 default_pm; | ||
34 | /* value to be written to XREG_AMPLITUDE in DVB-T mode (0: no write) */ | ||
35 | u8 dvb_amplitude; | ||
36 | /* if non-zero, register 0x0E is set to filter analog TV video output */ | ||
37 | u8 set_smoothedcvbs; | ||
38 | /* IF for DVB-T */ | ||
39 | u32 if_khz; | ||
40 | }; | ||
41 | |||
42 | /* xc4000 callback command */ | ||
43 | #define XC4000_TUNER_RESET 0 | ||
44 | |||
45 | /* For each bridge framework, when it attaches either analog or digital, | ||
46 | * it has to store a reference back to its _core equivalent structure, | ||
47 | * so that it can service the hardware by steering gpio's etc. | ||
48 | * Each bridge implementation is different so cast devptr accordingly. | ||
49 | * The xc4000 driver cares not for this value, other than ensuring | ||
50 | * it's passed back to a bridge during tuner_callback(). | ||
51 | */ | ||
52 | |||
53 | #if defined(CONFIG_MEDIA_TUNER_XC4000) || (defined(CONFIG_MEDIA_TUNER_XC4000_MODULE) && defined(MODULE)) | ||
54 | extern struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe, | ||
55 | struct i2c_adapter *i2c, | ||
56 | struct xc4000_config *cfg); | ||
57 | #else | ||
58 | static inline struct dvb_frontend *xc4000_attach(struct dvb_frontend *fe, | ||
59 | struct i2c_adapter *i2c, | ||
60 | struct xc4000_config *cfg) | ||
61 | { | ||
62 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
63 | return NULL; | ||
64 | } | ||
65 | #endif | ||
66 | |||
67 | #endif | ||
diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c new file mode 100644 index 000000000000..dc93cf338f36 --- /dev/null +++ b/drivers/media/tuners/xc5000.c | |||
@@ -0,0 +1,1366 @@ | |||
1 | /* | ||
2 | * Driver for Xceive XC5000 "QAM/8VSB single chip tuner" | ||
3 | * | ||
4 | * Copyright (c) 2007 Xceive Corporation | ||
5 | * Copyright (c) 2007 Steven Toth <stoth@linuxtv.org> | ||
6 | * Copyright (c) 2009 Devin Heitmueller <dheitmueller@kernellabs.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
22 | */ | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/moduleparam.h> | ||
26 | #include <linux/videodev2.h> | ||
27 | #include <linux/delay.h> | ||
28 | #include <linux/dvb/frontend.h> | ||
29 | #include <linux/i2c.h> | ||
30 | |||
31 | #include "dvb_frontend.h" | ||
32 | |||
33 | #include "xc5000.h" | ||
34 | #include "tuner-i2c.h" | ||
35 | |||
36 | static int debug; | ||
37 | module_param(debug, int, 0644); | ||
38 | MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); | ||
39 | |||
40 | static int no_poweroff; | ||
41 | module_param(no_poweroff, int, 0644); | ||
42 | MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n" | ||
43 | "\t\t1 keep device energized and with tuner ready all the times.\n" | ||
44 | "\t\tFaster, but consumes more power and keeps the device hotter"); | ||
45 | |||
46 | static DEFINE_MUTEX(xc5000_list_mutex); | ||
47 | static LIST_HEAD(hybrid_tuner_instance_list); | ||
48 | |||
49 | #define dprintk(level, fmt, arg...) if (debug >= level) \ | ||
50 | printk(KERN_INFO "%s: " fmt, "xc5000", ## arg) | ||
51 | |||
52 | struct xc5000_priv { | ||
53 | struct tuner_i2c_props i2c_props; | ||
54 | struct list_head hybrid_tuner_instance_list; | ||
55 | |||
56 | u32 if_khz; | ||
57 | u16 xtal_khz; | ||
58 | u32 freq_hz; | ||
59 | u32 bandwidth; | ||
60 | u8 video_standard; | ||
61 | u8 rf_mode; | ||
62 | u8 radio_input; | ||
63 | |||
64 | int chip_id; | ||
65 | u16 pll_register_no; | ||
66 | u8 init_status_supported; | ||
67 | u8 fw_checksum_supported; | ||
68 | }; | ||
69 | |||
70 | /* Misc Defines */ | ||
71 | #define MAX_TV_STANDARD 24 | ||
72 | #define XC_MAX_I2C_WRITE_LENGTH 64 | ||
73 | |||
74 | /* Signal Types */ | ||
75 | #define XC_RF_MODE_AIR 0 | ||
76 | #define XC_RF_MODE_CABLE 1 | ||
77 | |||
78 | /* Result codes */ | ||
79 | #define XC_RESULT_SUCCESS 0 | ||
80 | #define XC_RESULT_RESET_FAILURE 1 | ||
81 | #define XC_RESULT_I2C_WRITE_FAILURE 2 | ||
82 | #define XC_RESULT_I2C_READ_FAILURE 3 | ||
83 | #define XC_RESULT_OUT_OF_RANGE 5 | ||
84 | |||
85 | /* Product id */ | ||
86 | #define XC_PRODUCT_ID_FW_NOT_LOADED 0x2000 | ||
87 | #define XC_PRODUCT_ID_FW_LOADED 0x1388 | ||
88 | |||
89 | /* Registers */ | ||
90 | #define XREG_INIT 0x00 | ||
91 | #define XREG_VIDEO_MODE 0x01 | ||
92 | #define XREG_AUDIO_MODE 0x02 | ||
93 | #define XREG_RF_FREQ 0x03 | ||
94 | #define XREG_D_CODE 0x04 | ||
95 | #define XREG_IF_OUT 0x05 | ||
96 | #define XREG_SEEK_MODE 0x07 | ||
97 | #define XREG_POWER_DOWN 0x0A /* Obsolete */ | ||
98 | /* Set the output amplitude - SIF for analog, DTVP/DTVN for digital */ | ||
99 | #define XREG_OUTPUT_AMP 0x0B | ||
100 | #define XREG_SIGNALSOURCE 0x0D /* 0=Air, 1=Cable */ | ||
101 | #define XREG_SMOOTHEDCVBS 0x0E | ||
102 | #define XREG_XTALFREQ 0x0F | ||
103 | #define XREG_FINERFREQ 0x10 | ||
104 | #define XREG_DDIMODE 0x11 | ||
105 | |||
106 | #define XREG_ADC_ENV 0x00 | ||
107 | #define XREG_QUALITY 0x01 | ||
108 | #define XREG_FRAME_LINES 0x02 | ||
109 | #define XREG_HSYNC_FREQ 0x03 | ||
110 | #define XREG_LOCK 0x04 | ||
111 | #define XREG_FREQ_ERROR 0x05 | ||
112 | #define XREG_SNR 0x06 | ||
113 | #define XREG_VERSION 0x07 | ||
114 | #define XREG_PRODUCT_ID 0x08 | ||
115 | #define XREG_BUSY 0x09 | ||
116 | #define XREG_BUILD 0x0D | ||
117 | #define XREG_TOTALGAIN 0x0F | ||
118 | #define XREG_FW_CHECKSUM 0x12 | ||
119 | #define XREG_INIT_STATUS 0x13 | ||
120 | |||
121 | /* | ||
122 | Basic firmware description. This will remain with | ||
123 | the driver for documentation purposes. | ||
124 | |||
125 | This represents an I2C firmware file encoded as a | ||
126 | string of unsigned char. Format is as follows: | ||
127 | |||
128 | char[0 ]=len0_MSB -> len = len_MSB * 256 + len_LSB | ||
129 | char[1 ]=len0_LSB -> length of first write transaction | ||
130 | char[2 ]=data0 -> first byte to be sent | ||
131 | char[3 ]=data1 | ||
132 | char[4 ]=data2 | ||
133 | char[ ]=... | ||
134 | char[M ]=dataN -> last byte to be sent | ||
135 | char[M+1]=len1_MSB -> len = len_MSB * 256 + len_LSB | ||
136 | char[M+2]=len1_LSB -> length of second write transaction | ||
137 | char[M+3]=data0 | ||
138 | char[M+4]=data1 | ||
139 | ... | ||
140 | etc. | ||
141 | |||
142 | The [len] value should be interpreted as follows: | ||
143 | |||
144 | len= len_MSB _ len_LSB | ||
145 | len=1111_1111_1111_1111 : End of I2C_SEQUENCE | ||
146 | len=0000_0000_0000_0000 : Reset command: Do hardware reset | ||
147 | len=0NNN_NNNN_NNNN_NNNN : Normal transaction: number of bytes = {1:32767) | ||
148 | len=1WWW_WWWW_WWWW_WWWW : Wait command: wait for {1:32767} ms | ||
149 | |||
150 | For the RESET and WAIT commands, the two following bytes will contain | ||
151 | immediately the length of the following transaction. | ||
152 | |||
153 | */ | ||
154 | struct XC_TV_STANDARD { | ||
155 | char *Name; | ||
156 | u16 AudioMode; | ||
157 | u16 VideoMode; | ||
158 | }; | ||
159 | |||
160 | /* Tuner standards */ | ||
161 | #define MN_NTSC_PAL_BTSC 0 | ||
162 | #define MN_NTSC_PAL_A2 1 | ||
163 | #define MN_NTSC_PAL_EIAJ 2 | ||
164 | #define MN_NTSC_PAL_Mono 3 | ||
165 | #define BG_PAL_A2 4 | ||
166 | #define BG_PAL_NICAM 5 | ||
167 | #define BG_PAL_MONO 6 | ||
168 | #define I_PAL_NICAM 7 | ||
169 | #define I_PAL_NICAM_MONO 8 | ||
170 | #define DK_PAL_A2 9 | ||
171 | #define DK_PAL_NICAM 10 | ||
172 | #define DK_PAL_MONO 11 | ||
173 | #define DK_SECAM_A2DK1 12 | ||
174 | #define DK_SECAM_A2LDK3 13 | ||
175 | #define DK_SECAM_A2MONO 14 | ||
176 | #define L_SECAM_NICAM 15 | ||
177 | #define LC_SECAM_NICAM 16 | ||
178 | #define DTV6 17 | ||
179 | #define DTV8 18 | ||
180 | #define DTV7_8 19 | ||
181 | #define DTV7 20 | ||
182 | #define FM_Radio_INPUT2 21 | ||
183 | #define FM_Radio_INPUT1 22 | ||
184 | #define FM_Radio_INPUT1_MONO 23 | ||
185 | |||
186 | static struct XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = { | ||
187 | {"M/N-NTSC/PAL-BTSC", 0x0400, 0x8020}, | ||
188 | {"M/N-NTSC/PAL-A2", 0x0600, 0x8020}, | ||
189 | {"M/N-NTSC/PAL-EIAJ", 0x0440, 0x8020}, | ||
190 | {"M/N-NTSC/PAL-Mono", 0x0478, 0x8020}, | ||
191 | {"B/G-PAL-A2", 0x0A00, 0x8049}, | ||
192 | {"B/G-PAL-NICAM", 0x0C04, 0x8049}, | ||
193 | {"B/G-PAL-MONO", 0x0878, 0x8059}, | ||
194 | {"I-PAL-NICAM", 0x1080, 0x8009}, | ||
195 | {"I-PAL-NICAM-MONO", 0x0E78, 0x8009}, | ||
196 | {"D/K-PAL-A2", 0x1600, 0x8009}, | ||
197 | {"D/K-PAL-NICAM", 0x0E80, 0x8009}, | ||
198 | {"D/K-PAL-MONO", 0x1478, 0x8009}, | ||
199 | {"D/K-SECAM-A2 DK1", 0x1200, 0x8009}, | ||
200 | {"D/K-SECAM-A2 L/DK3", 0x0E00, 0x8009}, | ||
201 | {"D/K-SECAM-A2 MONO", 0x1478, 0x8009}, | ||
202 | {"L-SECAM-NICAM", 0x8E82, 0x0009}, | ||
203 | {"L'-SECAM-NICAM", 0x8E82, 0x4009}, | ||
204 | {"DTV6", 0x00C0, 0x8002}, | ||
205 | {"DTV8", 0x00C0, 0x800B}, | ||
206 | {"DTV7/8", 0x00C0, 0x801B}, | ||
207 | {"DTV7", 0x00C0, 0x8007}, | ||
208 | {"FM Radio-INPUT2", 0x9802, 0x9002}, | ||
209 | {"FM Radio-INPUT1", 0x0208, 0x9002}, | ||
210 | {"FM Radio-INPUT1_MONO", 0x0278, 0x9002} | ||
211 | }; | ||
212 | |||
213 | |||
214 | struct xc5000_fw_cfg { | ||
215 | char *name; | ||
216 | u16 size; | ||
217 | u16 pll_reg; | ||
218 | u8 init_status_supported; | ||
219 | u8 fw_checksum_supported; | ||
220 | }; | ||
221 | |||
222 | #define XC5000A_FIRMWARE "dvb-fe-xc5000-1.6.114.fw" | ||
223 | static const struct xc5000_fw_cfg xc5000a_1_6_114 = { | ||
224 | .name = XC5000A_FIRMWARE, | ||
225 | .size = 12401, | ||
226 | .pll_reg = 0x806c, | ||
227 | }; | ||
228 | |||
229 | #define XC5000C_FIRMWARE "dvb-fe-xc5000c-4.1.30.7.fw" | ||
230 | static const struct xc5000_fw_cfg xc5000c_41_024_5 = { | ||
231 | .name = XC5000C_FIRMWARE, | ||
232 | .size = 16497, | ||
233 | .pll_reg = 0x13, | ||
234 | .init_status_supported = 1, | ||
235 | .fw_checksum_supported = 1, | ||
236 | }; | ||
237 | |||
238 | static inline const struct xc5000_fw_cfg *xc5000_assign_firmware(int chip_id) | ||
239 | { | ||
240 | switch (chip_id) { | ||
241 | default: | ||
242 | case XC5000A: | ||
243 | return &xc5000a_1_6_114; | ||
244 | case XC5000C: | ||
245 | return &xc5000c_41_024_5; | ||
246 | } | ||
247 | } | ||
248 | |||
249 | static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe, int force); | ||
250 | static int xc5000_is_firmware_loaded(struct dvb_frontend *fe); | ||
251 | static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val); | ||
252 | static int xc5000_TunerReset(struct dvb_frontend *fe); | ||
253 | |||
254 | static int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len) | ||
255 | { | ||
256 | struct i2c_msg msg = { .addr = priv->i2c_props.addr, | ||
257 | .flags = 0, .buf = buf, .len = len }; | ||
258 | |||
259 | if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { | ||
260 | printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n", len); | ||
261 | return XC_RESULT_I2C_WRITE_FAILURE; | ||
262 | } | ||
263 | return XC_RESULT_SUCCESS; | ||
264 | } | ||
265 | |||
266 | #if 0 | ||
267 | /* This routine is never used because the only time we read data from the | ||
268 | i2c bus is when we read registers, and we want that to be an atomic i2c | ||
269 | transaction in case we are on a multi-master bus */ | ||
270 | static int xc_read_i2c_data(struct xc5000_priv *priv, u8 *buf, int len) | ||
271 | { | ||
272 | struct i2c_msg msg = { .addr = priv->i2c_props.addr, | ||
273 | .flags = I2C_M_RD, .buf = buf, .len = len }; | ||
274 | |||
275 | if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) { | ||
276 | printk(KERN_ERR "xc5000 I2C read failed (len=%i)\n", len); | ||
277 | return -EREMOTEIO; | ||
278 | } | ||
279 | return 0; | ||
280 | } | ||
281 | #endif | ||
282 | |||
283 | static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val) | ||
284 | { | ||
285 | u8 buf[2] = { reg >> 8, reg & 0xff }; | ||
286 | u8 bval[2] = { 0, 0 }; | ||
287 | struct i2c_msg msg[2] = { | ||
288 | { .addr = priv->i2c_props.addr, | ||
289 | .flags = 0, .buf = &buf[0], .len = 2 }, | ||
290 | { .addr = priv->i2c_props.addr, | ||
291 | .flags = I2C_M_RD, .buf = &bval[0], .len = 2 }, | ||
292 | }; | ||
293 | |||
294 | if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) { | ||
295 | printk(KERN_WARNING "xc5000: I2C read failed\n"); | ||
296 | return -EREMOTEIO; | ||
297 | } | ||
298 | |||
299 | *val = (bval[0] << 8) | bval[1]; | ||
300 | return XC_RESULT_SUCCESS; | ||
301 | } | ||
302 | |||
303 | static void xc_wait(int wait_ms) | ||
304 | { | ||
305 | msleep(wait_ms); | ||
306 | } | ||
307 | |||
308 | static int xc5000_TunerReset(struct dvb_frontend *fe) | ||
309 | { | ||
310 | struct xc5000_priv *priv = fe->tuner_priv; | ||
311 | int ret; | ||
312 | |||
313 | dprintk(1, "%s()\n", __func__); | ||
314 | |||
315 | if (fe->callback) { | ||
316 | ret = fe->callback(((fe->dvb) && (fe->dvb->priv)) ? | ||
317 | fe->dvb->priv : | ||
318 | priv->i2c_props.adap->algo_data, | ||
319 | DVB_FRONTEND_COMPONENT_TUNER, | ||
320 | XC5000_TUNER_RESET, 0); | ||
321 | if (ret) { | ||
322 | printk(KERN_ERR "xc5000: reset failed\n"); | ||
323 | return XC_RESULT_RESET_FAILURE; | ||
324 | } | ||
325 | } else { | ||
326 | printk(KERN_ERR "xc5000: no tuner reset callback function, fatal\n"); | ||
327 | return XC_RESULT_RESET_FAILURE; | ||
328 | } | ||
329 | return XC_RESULT_SUCCESS; | ||
330 | } | ||
331 | |||
332 | static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData) | ||
333 | { | ||
334 | u8 buf[4]; | ||
335 | int WatchDogTimer = 100; | ||
336 | int result; | ||
337 | |||
338 | buf[0] = (regAddr >> 8) & 0xFF; | ||
339 | buf[1] = regAddr & 0xFF; | ||
340 | buf[2] = (i2cData >> 8) & 0xFF; | ||
341 | buf[3] = i2cData & 0xFF; | ||
342 | result = xc_send_i2c_data(priv, buf, 4); | ||
343 | if (result == XC_RESULT_SUCCESS) { | ||
344 | /* wait for busy flag to clear */ | ||
345 | while ((WatchDogTimer > 0) && (result == XC_RESULT_SUCCESS)) { | ||
346 | result = xc5000_readreg(priv, XREG_BUSY, (u16 *)buf); | ||
347 | if (result == XC_RESULT_SUCCESS) { | ||
348 | if ((buf[0] == 0) && (buf[1] == 0)) { | ||
349 | /* busy flag cleared */ | ||
350 | break; | ||
351 | } else { | ||
352 | xc_wait(5); /* wait 5 ms */ | ||
353 | WatchDogTimer--; | ||
354 | } | ||
355 | } | ||
356 | } | ||
357 | } | ||
358 | if (WatchDogTimer <= 0) | ||
359 | result = XC_RESULT_I2C_WRITE_FAILURE; | ||
360 | |||
361 | return result; | ||
362 | } | ||
363 | |||
364 | static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence) | ||
365 | { | ||
366 | struct xc5000_priv *priv = fe->tuner_priv; | ||
367 | |||
368 | int i, nbytes_to_send, result; | ||
369 | unsigned int len, pos, index; | ||
370 | u8 buf[XC_MAX_I2C_WRITE_LENGTH]; | ||
371 | |||
372 | index = 0; | ||
373 | while ((i2c_sequence[index] != 0xFF) || | ||
374 | (i2c_sequence[index + 1] != 0xFF)) { | ||
375 | len = i2c_sequence[index] * 256 + i2c_sequence[index+1]; | ||
376 | if (len == 0x0000) { | ||
377 | /* RESET command */ | ||
378 | result = xc5000_TunerReset(fe); | ||
379 | index += 2; | ||
380 | if (result != XC_RESULT_SUCCESS) | ||
381 | return result; | ||
382 | } else if (len & 0x8000) { | ||
383 | /* WAIT command */ | ||
384 | xc_wait(len & 0x7FFF); | ||
385 | index += 2; | ||
386 | } else { | ||
387 | /* Send i2c data whilst ensuring individual transactions | ||
388 | * do not exceed XC_MAX_I2C_WRITE_LENGTH bytes. | ||
389 | */ | ||
390 | index += 2; | ||
391 | buf[0] = i2c_sequence[index]; | ||
392 | buf[1] = i2c_sequence[index + 1]; | ||
393 | pos = 2; | ||
394 | while (pos < len) { | ||
395 | if ((len - pos) > XC_MAX_I2C_WRITE_LENGTH - 2) | ||
396 | nbytes_to_send = | ||
397 | XC_MAX_I2C_WRITE_LENGTH; | ||
398 | else | ||
399 | nbytes_to_send = (len - pos + 2); | ||
400 | for (i = 2; i < nbytes_to_send; i++) { | ||
401 | buf[i] = i2c_sequence[index + pos + | ||
402 | i - 2]; | ||
403 | } | ||
404 | result = xc_send_i2c_data(priv, buf, | ||
405 | nbytes_to_send); | ||
406 | |||
407 | if (result != XC_RESULT_SUCCESS) | ||
408 | return result; | ||
409 | |||
410 | pos += nbytes_to_send - 2; | ||
411 | } | ||
412 | index += len; | ||
413 | } | ||
414 | } | ||
415 | return XC_RESULT_SUCCESS; | ||
416 | } | ||
417 | |||
418 | static int xc_initialize(struct xc5000_priv *priv) | ||
419 | { | ||
420 | dprintk(1, "%s()\n", __func__); | ||
421 | return xc_write_reg(priv, XREG_INIT, 0); | ||
422 | } | ||
423 | |||
424 | static int xc_SetTVStandard(struct xc5000_priv *priv, | ||
425 | u16 VideoMode, u16 AudioMode) | ||
426 | { | ||
427 | int ret; | ||
428 | dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, VideoMode, AudioMode); | ||
429 | dprintk(1, "%s() Standard = %s\n", | ||
430 | __func__, | ||
431 | XC5000_Standard[priv->video_standard].Name); | ||
432 | |||
433 | ret = xc_write_reg(priv, XREG_VIDEO_MODE, VideoMode); | ||
434 | if (ret == XC_RESULT_SUCCESS) | ||
435 | ret = xc_write_reg(priv, XREG_AUDIO_MODE, AudioMode); | ||
436 | |||
437 | return ret; | ||
438 | } | ||
439 | |||
440 | static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode) | ||
441 | { | ||
442 | dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode, | ||
443 | rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE"); | ||
444 | |||
445 | if ((rf_mode != XC_RF_MODE_AIR) && (rf_mode != XC_RF_MODE_CABLE)) { | ||
446 | rf_mode = XC_RF_MODE_CABLE; | ||
447 | printk(KERN_ERR | ||
448 | "%s(), Invalid mode, defaulting to CABLE", | ||
449 | __func__); | ||
450 | } | ||
451 | return xc_write_reg(priv, XREG_SIGNALSOURCE, rf_mode); | ||
452 | } | ||
453 | |||
454 | static const struct dvb_tuner_ops xc5000_tuner_ops; | ||
455 | |||
456 | static int xc_set_RF_frequency(struct xc5000_priv *priv, u32 freq_hz) | ||
457 | { | ||
458 | u16 freq_code; | ||
459 | |||
460 | dprintk(1, "%s(%u)\n", __func__, freq_hz); | ||
461 | |||
462 | if ((freq_hz > xc5000_tuner_ops.info.frequency_max) || | ||
463 | (freq_hz < xc5000_tuner_ops.info.frequency_min)) | ||
464 | return XC_RESULT_OUT_OF_RANGE; | ||
465 | |||
466 | freq_code = (u16)(freq_hz / 15625); | ||
467 | |||
468 | /* Starting in firmware version 1.1.44, Xceive recommends using the | ||
469 | FINERFREQ for all normal tuning (the doc indicates reg 0x03 should | ||
470 | only be used for fast scanning for channel lock) */ | ||
471 | return xc_write_reg(priv, XREG_FINERFREQ, freq_code); | ||
472 | } | ||
473 | |||
474 | |||
475 | static int xc_set_IF_frequency(struct xc5000_priv *priv, u32 freq_khz) | ||
476 | { | ||
477 | u32 freq_code = (freq_khz * 1024)/1000; | ||
478 | dprintk(1, "%s(freq_khz = %d) freq_code = 0x%x\n", | ||
479 | __func__, freq_khz, freq_code); | ||
480 | |||
481 | return xc_write_reg(priv, XREG_IF_OUT, freq_code); | ||
482 | } | ||
483 | |||
484 | |||
485 | static int xc_get_ADC_Envelope(struct xc5000_priv *priv, u16 *adc_envelope) | ||
486 | { | ||
487 | return xc5000_readreg(priv, XREG_ADC_ENV, adc_envelope); | ||
488 | } | ||
489 | |||
490 | static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz) | ||
491 | { | ||
492 | int result; | ||
493 | u16 regData; | ||
494 | u32 tmp; | ||
495 | |||
496 | result = xc5000_readreg(priv, XREG_FREQ_ERROR, ®Data); | ||
497 | if (result != XC_RESULT_SUCCESS) | ||
498 | return result; | ||
499 | |||
500 | tmp = (u32)regData; | ||
501 | (*freq_error_hz) = (tmp * 15625) / 1000; | ||
502 | return result; | ||
503 | } | ||
504 | |||
505 | static int xc_get_lock_status(struct xc5000_priv *priv, u16 *lock_status) | ||
506 | { | ||
507 | return xc5000_readreg(priv, XREG_LOCK, lock_status); | ||
508 | } | ||
509 | |||
510 | static int xc_get_version(struct xc5000_priv *priv, | ||
511 | u8 *hw_majorversion, u8 *hw_minorversion, | ||
512 | u8 *fw_majorversion, u8 *fw_minorversion) | ||
513 | { | ||
514 | u16 data; | ||
515 | int result; | ||
516 | |||
517 | result = xc5000_readreg(priv, XREG_VERSION, &data); | ||
518 | if (result != XC_RESULT_SUCCESS) | ||
519 | return result; | ||
520 | |||
521 | (*hw_majorversion) = (data >> 12) & 0x0F; | ||
522 | (*hw_minorversion) = (data >> 8) & 0x0F; | ||
523 | (*fw_majorversion) = (data >> 4) & 0x0F; | ||
524 | (*fw_minorversion) = data & 0x0F; | ||
525 | |||
526 | return 0; | ||
527 | } | ||
528 | |||
529 | static int xc_get_buildversion(struct xc5000_priv *priv, u16 *buildrev) | ||
530 | { | ||
531 | return xc5000_readreg(priv, XREG_BUILD, buildrev); | ||
532 | } | ||
533 | |||
534 | static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz) | ||
535 | { | ||
536 | u16 regData; | ||
537 | int result; | ||
538 | |||
539 | result = xc5000_readreg(priv, XREG_HSYNC_FREQ, ®Data); | ||
540 | if (result != XC_RESULT_SUCCESS) | ||
541 | return result; | ||
542 | |||
543 | (*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100; | ||
544 | return result; | ||
545 | } | ||
546 | |||
547 | static int xc_get_frame_lines(struct xc5000_priv *priv, u16 *frame_lines) | ||
548 | { | ||
549 | return xc5000_readreg(priv, XREG_FRAME_LINES, frame_lines); | ||
550 | } | ||
551 | |||
552 | static int xc_get_quality(struct xc5000_priv *priv, u16 *quality) | ||
553 | { | ||
554 | return xc5000_readreg(priv, XREG_QUALITY, quality); | ||
555 | } | ||
556 | |||
557 | static int xc_get_analogsnr(struct xc5000_priv *priv, u16 *snr) | ||
558 | { | ||
559 | return xc5000_readreg(priv, XREG_SNR, snr); | ||
560 | } | ||
561 | |||
562 | static int xc_get_totalgain(struct xc5000_priv *priv, u16 *totalgain) | ||
563 | { | ||
564 | return xc5000_readreg(priv, XREG_TOTALGAIN, totalgain); | ||
565 | } | ||
566 | |||
567 | static u16 WaitForLock(struct xc5000_priv *priv) | ||
568 | { | ||
569 | u16 lockState = 0; | ||
570 | int watchDogCount = 40; | ||
571 | |||
572 | while ((lockState == 0) && (watchDogCount > 0)) { | ||
573 | xc_get_lock_status(priv, &lockState); | ||
574 | if (lockState != 1) { | ||
575 | xc_wait(5); | ||
576 | watchDogCount--; | ||
577 | } | ||
578 | } | ||
579 | return lockState; | ||
580 | } | ||
581 | |||
582 | #define XC_TUNE_ANALOG 0 | ||
583 | #define XC_TUNE_DIGITAL 1 | ||
584 | static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz, int mode) | ||
585 | { | ||
586 | int found = 0; | ||
587 | |||
588 | dprintk(1, "%s(%u)\n", __func__, freq_hz); | ||
589 | |||
590 | if (xc_set_RF_frequency(priv, freq_hz) != XC_RESULT_SUCCESS) | ||
591 | return 0; | ||
592 | |||
593 | if (mode == XC_TUNE_ANALOG) { | ||
594 | if (WaitForLock(priv) == 1) | ||
595 | found = 1; | ||
596 | } | ||
597 | |||
598 | return found; | ||
599 | } | ||
600 | |||
601 | static int xc_set_xtal(struct dvb_frontend *fe) | ||
602 | { | ||
603 | struct xc5000_priv *priv = fe->tuner_priv; | ||
604 | int ret = XC_RESULT_SUCCESS; | ||
605 | |||
606 | switch (priv->chip_id) { | ||
607 | default: | ||
608 | case XC5000A: | ||
609 | /* 32.000 MHz xtal is default */ | ||
610 | break; | ||
611 | case XC5000C: | ||
612 | switch (priv->xtal_khz) { | ||
613 | default: | ||
614 | case 32000: | ||
615 | /* 32.000 MHz xtal is default */ | ||
616 | break; | ||
617 | case 31875: | ||
618 | /* 31.875 MHz xtal configuration */ | ||
619 | ret = xc_write_reg(priv, 0x000f, 0x8081); | ||
620 | break; | ||
621 | } | ||
622 | break; | ||
623 | } | ||
624 | return ret; | ||
625 | } | ||
626 | |||
627 | static int xc5000_fwupload(struct dvb_frontend *fe) | ||
628 | { | ||
629 | struct xc5000_priv *priv = fe->tuner_priv; | ||
630 | const struct firmware *fw; | ||
631 | int ret; | ||
632 | const struct xc5000_fw_cfg *desired_fw = | ||
633 | xc5000_assign_firmware(priv->chip_id); | ||
634 | priv->pll_register_no = desired_fw->pll_reg; | ||
635 | priv->init_status_supported = desired_fw->init_status_supported; | ||
636 | priv->fw_checksum_supported = desired_fw->fw_checksum_supported; | ||
637 | |||
638 | /* request the firmware, this will block and timeout */ | ||
639 | printk(KERN_INFO "xc5000: waiting for firmware upload (%s)...\n", | ||
640 | desired_fw->name); | ||
641 | |||
642 | ret = request_firmware(&fw, desired_fw->name, | ||
643 | priv->i2c_props.adap->dev.parent); | ||
644 | if (ret) { | ||
645 | printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n"); | ||
646 | ret = XC_RESULT_RESET_FAILURE; | ||
647 | goto out; | ||
648 | } else { | ||
649 | printk(KERN_DEBUG "xc5000: firmware read %Zu bytes.\n", | ||
650 | fw->size); | ||
651 | ret = XC_RESULT_SUCCESS; | ||
652 | } | ||
653 | |||
654 | if (fw->size != desired_fw->size) { | ||
655 | printk(KERN_ERR "xc5000: firmware incorrect size\n"); | ||
656 | ret = XC_RESULT_RESET_FAILURE; | ||
657 | } else { | ||
658 | printk(KERN_INFO "xc5000: firmware uploading...\n"); | ||
659 | ret = xc_load_i2c_sequence(fe, fw->data); | ||
660 | if (XC_RESULT_SUCCESS == ret) | ||
661 | ret = xc_set_xtal(fe); | ||
662 | if (XC_RESULT_SUCCESS == ret) | ||
663 | printk(KERN_INFO "xc5000: firmware upload complete...\n"); | ||
664 | else | ||
665 | printk(KERN_ERR "xc5000: firmware upload failed...\n"); | ||
666 | } | ||
667 | |||
668 | out: | ||
669 | release_firmware(fw); | ||
670 | return ret; | ||
671 | } | ||
672 | |||
673 | static void xc_debug_dump(struct xc5000_priv *priv) | ||
674 | { | ||
675 | u16 adc_envelope; | ||
676 | u32 freq_error_hz = 0; | ||
677 | u16 lock_status; | ||
678 | u32 hsync_freq_hz = 0; | ||
679 | u16 frame_lines; | ||
680 | u16 quality; | ||
681 | u16 snr; | ||
682 | u16 totalgain; | ||
683 | u8 hw_majorversion = 0, hw_minorversion = 0; | ||
684 | u8 fw_majorversion = 0, fw_minorversion = 0; | ||
685 | u16 fw_buildversion = 0; | ||
686 | u16 regval; | ||
687 | |||
688 | /* Wait for stats to stabilize. | ||
689 | * Frame Lines needs two frame times after initial lock | ||
690 | * before it is valid. | ||
691 | */ | ||
692 | xc_wait(100); | ||
693 | |||
694 | xc_get_ADC_Envelope(priv, &adc_envelope); | ||
695 | dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope); | ||
696 | |||
697 | xc_get_frequency_error(priv, &freq_error_hz); | ||
698 | dprintk(1, "*** Frequency error = %d Hz\n", freq_error_hz); | ||
699 | |||
700 | xc_get_lock_status(priv, &lock_status); | ||
701 | dprintk(1, "*** Lock status (0-Wait, 1-Locked, 2-No-signal) = %d\n", | ||
702 | lock_status); | ||
703 | |||
704 | xc_get_version(priv, &hw_majorversion, &hw_minorversion, | ||
705 | &fw_majorversion, &fw_minorversion); | ||
706 | xc_get_buildversion(priv, &fw_buildversion); | ||
707 | dprintk(1, "*** HW: V%d.%d, FW: V %d.%d.%d\n", | ||
708 | hw_majorversion, hw_minorversion, | ||
709 | fw_majorversion, fw_minorversion, fw_buildversion); | ||
710 | |||
711 | xc_get_hsync_freq(priv, &hsync_freq_hz); | ||
712 | dprintk(1, "*** Horizontal sync frequency = %d Hz\n", hsync_freq_hz); | ||
713 | |||
714 | xc_get_frame_lines(priv, &frame_lines); | ||
715 | dprintk(1, "*** Frame lines = %d\n", frame_lines); | ||
716 | |||
717 | xc_get_quality(priv, &quality); | ||
718 | dprintk(1, "*** Quality (0:<8dB, 7:>56dB) = %d\n", quality & 0x07); | ||
719 | |||
720 | xc_get_analogsnr(priv, &snr); | ||
721 | dprintk(1, "*** Unweighted analog SNR = %d dB\n", snr & 0x3f); | ||
722 | |||
723 | xc_get_totalgain(priv, &totalgain); | ||
724 | dprintk(1, "*** Total gain = %d.%d dB\n", totalgain / 256, | ||
725 | (totalgain % 256) * 100 / 256); | ||
726 | |||
727 | if (priv->pll_register_no) { | ||
728 | xc5000_readreg(priv, priv->pll_register_no, ®val); | ||
729 | dprintk(1, "*** PLL lock status = 0x%04x\n", regval); | ||
730 | } | ||
731 | } | ||
732 | |||
733 | static int xc5000_set_params(struct dvb_frontend *fe) | ||
734 | { | ||
735 | int ret, b; | ||
736 | struct xc5000_priv *priv = fe->tuner_priv; | ||
737 | u32 bw = fe->dtv_property_cache.bandwidth_hz; | ||
738 | u32 freq = fe->dtv_property_cache.frequency; | ||
739 | u32 delsys = fe->dtv_property_cache.delivery_system; | ||
740 | |||
741 | if (xc_load_fw_and_init_tuner(fe, 0) != XC_RESULT_SUCCESS) { | ||
742 | dprintk(1, "Unable to load firmware and init tuner\n"); | ||
743 | return -EINVAL; | ||
744 | } | ||
745 | |||
746 | dprintk(1, "%s() frequency=%d (Hz)\n", __func__, freq); | ||
747 | |||
748 | switch (delsys) { | ||
749 | case SYS_ATSC: | ||
750 | dprintk(1, "%s() VSB modulation\n", __func__); | ||
751 | priv->rf_mode = XC_RF_MODE_AIR; | ||
752 | priv->freq_hz = freq - 1750000; | ||
753 | priv->video_standard = DTV6; | ||
754 | break; | ||
755 | case SYS_DVBC_ANNEX_B: | ||
756 | dprintk(1, "%s() QAM modulation\n", __func__); | ||
757 | priv->rf_mode = XC_RF_MODE_CABLE; | ||
758 | priv->freq_hz = freq - 1750000; | ||
759 | priv->video_standard = DTV6; | ||
760 | break; | ||
761 | case SYS_ISDBT: | ||
762 | /* All ISDB-T are currently for 6 MHz bw */ | ||
763 | if (!bw) | ||
764 | bw = 6000000; | ||
765 | /* fall to OFDM handling */ | ||
766 | case SYS_DMBTH: | ||
767 | case SYS_DVBT: | ||
768 | case SYS_DVBT2: | ||
769 | dprintk(1, "%s() OFDM\n", __func__); | ||
770 | switch (bw) { | ||
771 | case 6000000: | ||
772 | priv->video_standard = DTV6; | ||
773 | priv->freq_hz = freq - 1750000; | ||
774 | break; | ||
775 | case 7000000: | ||
776 | priv->video_standard = DTV7; | ||
777 | priv->freq_hz = freq - 2250000; | ||
778 | break; | ||
779 | case 8000000: | ||
780 | priv->video_standard = DTV8; | ||
781 | priv->freq_hz = freq - 2750000; | ||
782 | break; | ||
783 | default: | ||
784 | printk(KERN_ERR "xc5000 bandwidth not set!\n"); | ||
785 | return -EINVAL; | ||
786 | } | ||
787 | priv->rf_mode = XC_RF_MODE_AIR; | ||
788 | case SYS_DVBC_ANNEX_A: | ||
789 | case SYS_DVBC_ANNEX_C: | ||
790 | dprintk(1, "%s() QAM modulation\n", __func__); | ||
791 | priv->rf_mode = XC_RF_MODE_CABLE; | ||
792 | if (bw <= 6000000) { | ||
793 | priv->video_standard = DTV6; | ||
794 | priv->freq_hz = freq - 1750000; | ||
795 | b = 6; | ||
796 | } else if (bw <= 7000000) { | ||
797 | priv->video_standard = DTV7; | ||
798 | priv->freq_hz = freq - 2250000; | ||
799 | b = 7; | ||
800 | } else { | ||
801 | priv->video_standard = DTV7_8; | ||
802 | priv->freq_hz = freq - 2750000; | ||
803 | b = 8; | ||
804 | } | ||
805 | dprintk(1, "%s() Bandwidth %dMHz (%d)\n", __func__, | ||
806 | b, bw); | ||
807 | break; | ||
808 | default: | ||
809 | printk(KERN_ERR "xc5000: delivery system is not supported!\n"); | ||
810 | return -EINVAL; | ||
811 | } | ||
812 | |||
813 | dprintk(1, "%s() frequency=%d (compensated to %d)\n", | ||
814 | __func__, freq, priv->freq_hz); | ||
815 | |||
816 | ret = xc_SetSignalSource(priv, priv->rf_mode); | ||
817 | if (ret != XC_RESULT_SUCCESS) { | ||
818 | printk(KERN_ERR | ||
819 | "xc5000: xc_SetSignalSource(%d) failed\n", | ||
820 | priv->rf_mode); | ||
821 | return -EREMOTEIO; | ||
822 | } | ||
823 | |||
824 | ret = xc_SetTVStandard(priv, | ||
825 | XC5000_Standard[priv->video_standard].VideoMode, | ||
826 | XC5000_Standard[priv->video_standard].AudioMode); | ||
827 | if (ret != XC_RESULT_SUCCESS) { | ||
828 | printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n"); | ||
829 | return -EREMOTEIO; | ||
830 | } | ||
831 | |||
832 | ret = xc_set_IF_frequency(priv, priv->if_khz); | ||
833 | if (ret != XC_RESULT_SUCCESS) { | ||
834 | printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n", | ||
835 | priv->if_khz); | ||
836 | return -EIO; | ||
837 | } | ||
838 | |||
839 | xc_write_reg(priv, XREG_OUTPUT_AMP, 0x8a); | ||
840 | |||
841 | xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL); | ||
842 | |||
843 | if (debug) | ||
844 | xc_debug_dump(priv); | ||
845 | |||
846 | priv->bandwidth = bw; | ||
847 | |||
848 | return 0; | ||
849 | } | ||
850 | |||
851 | static int xc5000_is_firmware_loaded(struct dvb_frontend *fe) | ||
852 | { | ||
853 | struct xc5000_priv *priv = fe->tuner_priv; | ||
854 | int ret; | ||
855 | u16 id; | ||
856 | |||
857 | ret = xc5000_readreg(priv, XREG_PRODUCT_ID, &id); | ||
858 | if (ret == XC_RESULT_SUCCESS) { | ||
859 | if (id == XC_PRODUCT_ID_FW_NOT_LOADED) | ||
860 | ret = XC_RESULT_RESET_FAILURE; | ||
861 | else | ||
862 | ret = XC_RESULT_SUCCESS; | ||
863 | } | ||
864 | |||
865 | dprintk(1, "%s() returns %s id = 0x%x\n", __func__, | ||
866 | ret == XC_RESULT_SUCCESS ? "True" : "False", id); | ||
867 | return ret; | ||
868 | } | ||
869 | |||
870 | static int xc5000_set_tv_freq(struct dvb_frontend *fe, | ||
871 | struct analog_parameters *params) | ||
872 | { | ||
873 | struct xc5000_priv *priv = fe->tuner_priv; | ||
874 | u16 pll_lock_status; | ||
875 | int ret; | ||
876 | |||
877 | dprintk(1, "%s() frequency=%d (in units of 62.5khz)\n", | ||
878 | __func__, params->frequency); | ||
879 | |||
880 | /* Fix me: it could be air. */ | ||
881 | priv->rf_mode = params->mode; | ||
882 | if (params->mode > XC_RF_MODE_CABLE) | ||
883 | priv->rf_mode = XC_RF_MODE_CABLE; | ||
884 | |||
885 | /* params->frequency is in units of 62.5khz */ | ||
886 | priv->freq_hz = params->frequency * 62500; | ||
887 | |||
888 | /* FIX ME: Some video standards may have several possible audio | ||
889 | standards. We simply default to one of them here. | ||
890 | */ | ||
891 | if (params->std & V4L2_STD_MN) { | ||
892 | /* default to BTSC audio standard */ | ||
893 | priv->video_standard = MN_NTSC_PAL_BTSC; | ||
894 | goto tune_channel; | ||
895 | } | ||
896 | |||
897 | if (params->std & V4L2_STD_PAL_BG) { | ||
898 | /* default to NICAM audio standard */ | ||
899 | priv->video_standard = BG_PAL_NICAM; | ||
900 | goto tune_channel; | ||
901 | } | ||
902 | |||
903 | if (params->std & V4L2_STD_PAL_I) { | ||
904 | /* default to NICAM audio standard */ | ||
905 | priv->video_standard = I_PAL_NICAM; | ||
906 | goto tune_channel; | ||
907 | } | ||
908 | |||
909 | if (params->std & V4L2_STD_PAL_DK) { | ||
910 | /* default to NICAM audio standard */ | ||
911 | priv->video_standard = DK_PAL_NICAM; | ||
912 | goto tune_channel; | ||
913 | } | ||
914 | |||
915 | if (params->std & V4L2_STD_SECAM_DK) { | ||
916 | /* default to A2 DK1 audio standard */ | ||
917 | priv->video_standard = DK_SECAM_A2DK1; | ||
918 | goto tune_channel; | ||
919 | } | ||
920 | |||
921 | if (params->std & V4L2_STD_SECAM_L) { | ||
922 | priv->video_standard = L_SECAM_NICAM; | ||
923 | goto tune_channel; | ||
924 | } | ||
925 | |||
926 | if (params->std & V4L2_STD_SECAM_LC) { | ||
927 | priv->video_standard = LC_SECAM_NICAM; | ||
928 | goto tune_channel; | ||
929 | } | ||
930 | |||
931 | tune_channel: | ||
932 | ret = xc_SetSignalSource(priv, priv->rf_mode); | ||
933 | if (ret != XC_RESULT_SUCCESS) { | ||
934 | printk(KERN_ERR | ||
935 | "xc5000: xc_SetSignalSource(%d) failed\n", | ||
936 | priv->rf_mode); | ||
937 | return -EREMOTEIO; | ||
938 | } | ||
939 | |||
940 | ret = xc_SetTVStandard(priv, | ||
941 | XC5000_Standard[priv->video_standard].VideoMode, | ||
942 | XC5000_Standard[priv->video_standard].AudioMode); | ||
943 | if (ret != XC_RESULT_SUCCESS) { | ||
944 | printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n"); | ||
945 | return -EREMOTEIO; | ||
946 | } | ||
947 | |||
948 | xc_write_reg(priv, XREG_OUTPUT_AMP, 0x09); | ||
949 | |||
950 | xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG); | ||
951 | |||
952 | if (debug) | ||
953 | xc_debug_dump(priv); | ||
954 | |||
955 | if (priv->pll_register_no != 0) { | ||
956 | msleep(20); | ||
957 | xc5000_readreg(priv, priv->pll_register_no, &pll_lock_status); | ||
958 | if (pll_lock_status > 63) { | ||
959 | /* PLL is unlocked, force reload of the firmware */ | ||
960 | dprintk(1, "xc5000: PLL not locked (0x%x). Reloading...\n", | ||
961 | pll_lock_status); | ||
962 | if (xc_load_fw_and_init_tuner(fe, 1) != XC_RESULT_SUCCESS) { | ||
963 | printk(KERN_ERR "xc5000: Unable to reload fw\n"); | ||
964 | return -EREMOTEIO; | ||
965 | } | ||
966 | goto tune_channel; | ||
967 | } | ||
968 | } | ||
969 | |||
970 | return 0; | ||
971 | } | ||
972 | |||
973 | static int xc5000_set_radio_freq(struct dvb_frontend *fe, | ||
974 | struct analog_parameters *params) | ||
975 | { | ||
976 | struct xc5000_priv *priv = fe->tuner_priv; | ||
977 | int ret = -EINVAL; | ||
978 | u8 radio_input; | ||
979 | |||
980 | dprintk(1, "%s() frequency=%d (in units of khz)\n", | ||
981 | __func__, params->frequency); | ||
982 | |||
983 | if (priv->radio_input == XC5000_RADIO_NOT_CONFIGURED) { | ||
984 | dprintk(1, "%s() radio input not configured\n", __func__); | ||
985 | return -EINVAL; | ||
986 | } | ||
987 | |||
988 | if (priv->radio_input == XC5000_RADIO_FM1) | ||
989 | radio_input = FM_Radio_INPUT1; | ||
990 | else if (priv->radio_input == XC5000_RADIO_FM2) | ||
991 | radio_input = FM_Radio_INPUT2; | ||
992 | else if (priv->radio_input == XC5000_RADIO_FM1_MONO) | ||
993 | radio_input = FM_Radio_INPUT1_MONO; | ||
994 | else { | ||
995 | dprintk(1, "%s() unknown radio input %d\n", __func__, | ||
996 | priv->radio_input); | ||
997 | return -EINVAL; | ||
998 | } | ||
999 | |||
1000 | priv->freq_hz = params->frequency * 125 / 2; | ||
1001 | |||
1002 | priv->rf_mode = XC_RF_MODE_AIR; | ||
1003 | |||
1004 | ret = xc_SetTVStandard(priv, XC5000_Standard[radio_input].VideoMode, | ||
1005 | XC5000_Standard[radio_input].AudioMode); | ||
1006 | |||
1007 | if (ret != XC_RESULT_SUCCESS) { | ||
1008 | printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n"); | ||
1009 | return -EREMOTEIO; | ||
1010 | } | ||
1011 | |||
1012 | ret = xc_SetSignalSource(priv, priv->rf_mode); | ||
1013 | if (ret != XC_RESULT_SUCCESS) { | ||
1014 | printk(KERN_ERR | ||
1015 | "xc5000: xc_SetSignalSource(%d) failed\n", | ||
1016 | priv->rf_mode); | ||
1017 | return -EREMOTEIO; | ||
1018 | } | ||
1019 | |||
1020 | if ((priv->radio_input == XC5000_RADIO_FM1) || | ||
1021 | (priv->radio_input == XC5000_RADIO_FM2)) | ||
1022 | xc_write_reg(priv, XREG_OUTPUT_AMP, 0x09); | ||
1023 | else if (priv->radio_input == XC5000_RADIO_FM1_MONO) | ||
1024 | xc_write_reg(priv, XREG_OUTPUT_AMP, 0x06); | ||
1025 | |||
1026 | xc_tune_channel(priv, priv->freq_hz, XC_TUNE_ANALOG); | ||
1027 | |||
1028 | return 0; | ||
1029 | } | ||
1030 | |||
1031 | static int xc5000_set_analog_params(struct dvb_frontend *fe, | ||
1032 | struct analog_parameters *params) | ||
1033 | { | ||
1034 | struct xc5000_priv *priv = fe->tuner_priv; | ||
1035 | int ret = -EINVAL; | ||
1036 | |||
1037 | if (priv->i2c_props.adap == NULL) | ||
1038 | return -EINVAL; | ||
1039 | |||
1040 | if (xc_load_fw_and_init_tuner(fe, 0) != XC_RESULT_SUCCESS) { | ||
1041 | dprintk(1, "Unable to load firmware and init tuner\n"); | ||
1042 | return -EINVAL; | ||
1043 | } | ||
1044 | |||
1045 | switch (params->mode) { | ||
1046 | case V4L2_TUNER_RADIO: | ||
1047 | ret = xc5000_set_radio_freq(fe, params); | ||
1048 | break; | ||
1049 | case V4L2_TUNER_ANALOG_TV: | ||
1050 | case V4L2_TUNER_DIGITAL_TV: | ||
1051 | ret = xc5000_set_tv_freq(fe, params); | ||
1052 | break; | ||
1053 | } | ||
1054 | |||
1055 | return ret; | ||
1056 | } | ||
1057 | |||
1058 | |||
1059 | static int xc5000_get_frequency(struct dvb_frontend *fe, u32 *freq) | ||
1060 | { | ||
1061 | struct xc5000_priv *priv = fe->tuner_priv; | ||
1062 | dprintk(1, "%s()\n", __func__); | ||
1063 | *freq = priv->freq_hz; | ||
1064 | return 0; | ||
1065 | } | ||
1066 | |||
1067 | static int xc5000_get_if_frequency(struct dvb_frontend *fe, u32 *freq) | ||
1068 | { | ||
1069 | struct xc5000_priv *priv = fe->tuner_priv; | ||
1070 | dprintk(1, "%s()\n", __func__); | ||
1071 | *freq = priv->if_khz * 1000; | ||
1072 | return 0; | ||
1073 | } | ||
1074 | |||
1075 | static int xc5000_get_bandwidth(struct dvb_frontend *fe, u32 *bw) | ||
1076 | { | ||
1077 | struct xc5000_priv *priv = fe->tuner_priv; | ||
1078 | dprintk(1, "%s()\n", __func__); | ||
1079 | |||
1080 | *bw = priv->bandwidth; | ||
1081 | return 0; | ||
1082 | } | ||
1083 | |||
1084 | static int xc5000_get_status(struct dvb_frontend *fe, u32 *status) | ||
1085 | { | ||
1086 | struct xc5000_priv *priv = fe->tuner_priv; | ||
1087 | u16 lock_status = 0; | ||
1088 | |||
1089 | xc_get_lock_status(priv, &lock_status); | ||
1090 | |||
1091 | dprintk(1, "%s() lock_status = 0x%08x\n", __func__, lock_status); | ||
1092 | |||
1093 | *status = lock_status; | ||
1094 | |||
1095 | return 0; | ||
1096 | } | ||
1097 | |||
1098 | static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe, int force) | ||
1099 | { | ||
1100 | struct xc5000_priv *priv = fe->tuner_priv; | ||
1101 | int ret = XC_RESULT_SUCCESS; | ||
1102 | u16 pll_lock_status; | ||
1103 | u16 fw_ck; | ||
1104 | |||
1105 | if (force || xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) { | ||
1106 | |||
1107 | fw_retry: | ||
1108 | |||
1109 | ret = xc5000_fwupload(fe); | ||
1110 | if (ret != XC_RESULT_SUCCESS) | ||
1111 | return ret; | ||
1112 | |||
1113 | msleep(20); | ||
1114 | |||
1115 | if (priv->fw_checksum_supported) { | ||
1116 | if (xc5000_readreg(priv, XREG_FW_CHECKSUM, &fw_ck) | ||
1117 | != XC_RESULT_SUCCESS) { | ||
1118 | dprintk(1, "%s() FW checksum reading failed.\n", | ||
1119 | __func__); | ||
1120 | goto fw_retry; | ||
1121 | } | ||
1122 | |||
1123 | if (fw_ck == 0) { | ||
1124 | dprintk(1, "%s() FW checksum failed = 0x%04x\n", | ||
1125 | __func__, fw_ck); | ||
1126 | goto fw_retry; | ||
1127 | } | ||
1128 | } | ||
1129 | |||
1130 | /* Start the tuner self-calibration process */ | ||
1131 | ret |= xc_initialize(priv); | ||
1132 | |||
1133 | if (ret != XC_RESULT_SUCCESS) | ||
1134 | goto fw_retry; | ||
1135 | |||
1136 | /* Wait for calibration to complete. | ||
1137 | * We could continue but XC5000 will clock stretch subsequent | ||
1138 | * I2C transactions until calibration is complete. This way we | ||
1139 | * don't have to rely on clock stretching working. | ||
1140 | */ | ||
1141 | xc_wait(100); | ||
1142 | |||
1143 | if (priv->init_status_supported) { | ||
1144 | if (xc5000_readreg(priv, XREG_INIT_STATUS, &fw_ck) != XC_RESULT_SUCCESS) { | ||
1145 | dprintk(1, "%s() FW failed reading init status.\n", | ||
1146 | __func__); | ||
1147 | goto fw_retry; | ||
1148 | } | ||
1149 | |||
1150 | if (fw_ck == 0) { | ||
1151 | dprintk(1, "%s() FW init status failed = 0x%04x\n", __func__, fw_ck); | ||
1152 | goto fw_retry; | ||
1153 | } | ||
1154 | } | ||
1155 | |||
1156 | if (priv->pll_register_no) { | ||
1157 | xc5000_readreg(priv, priv->pll_register_no, | ||
1158 | &pll_lock_status); | ||
1159 | if (pll_lock_status > 63) { | ||
1160 | /* PLL is unlocked, force reload of the firmware */ | ||
1161 | printk(KERN_ERR "xc5000: PLL not running after fwload.\n"); | ||
1162 | goto fw_retry; | ||
1163 | } | ||
1164 | } | ||
1165 | |||
1166 | /* Default to "CABLE" mode */ | ||
1167 | ret |= xc_write_reg(priv, XREG_SIGNALSOURCE, XC_RF_MODE_CABLE); | ||
1168 | } | ||
1169 | |||
1170 | return ret; | ||
1171 | } | ||
1172 | |||
1173 | static int xc5000_sleep(struct dvb_frontend *fe) | ||
1174 | { | ||
1175 | int ret; | ||
1176 | |||
1177 | dprintk(1, "%s()\n", __func__); | ||
1178 | |||
1179 | /* Avoid firmware reload on slow devices */ | ||
1180 | if (no_poweroff) | ||
1181 | return 0; | ||
1182 | |||
1183 | /* According to Xceive technical support, the "powerdown" register | ||
1184 | was removed in newer versions of the firmware. The "supported" | ||
1185 | way to sleep the tuner is to pull the reset pin low for 10ms */ | ||
1186 | ret = xc5000_TunerReset(fe); | ||
1187 | if (ret != XC_RESULT_SUCCESS) { | ||
1188 | printk(KERN_ERR | ||
1189 | "xc5000: %s() unable to shutdown tuner\n", | ||
1190 | __func__); | ||
1191 | return -EREMOTEIO; | ||
1192 | } else | ||
1193 | return XC_RESULT_SUCCESS; | ||
1194 | } | ||
1195 | |||
1196 | static int xc5000_init(struct dvb_frontend *fe) | ||
1197 | { | ||
1198 | struct xc5000_priv *priv = fe->tuner_priv; | ||
1199 | dprintk(1, "%s()\n", __func__); | ||
1200 | |||
1201 | if (xc_load_fw_and_init_tuner(fe, 0) != XC_RESULT_SUCCESS) { | ||
1202 | printk(KERN_ERR "xc5000: Unable to initialise tuner\n"); | ||
1203 | return -EREMOTEIO; | ||
1204 | } | ||
1205 | |||
1206 | if (debug) | ||
1207 | xc_debug_dump(priv); | ||
1208 | |||
1209 | return 0; | ||
1210 | } | ||
1211 | |||
1212 | static int xc5000_release(struct dvb_frontend *fe) | ||
1213 | { | ||
1214 | struct xc5000_priv *priv = fe->tuner_priv; | ||
1215 | |||
1216 | dprintk(1, "%s()\n", __func__); | ||
1217 | |||
1218 | mutex_lock(&xc5000_list_mutex); | ||
1219 | |||
1220 | if (priv) | ||
1221 | hybrid_tuner_release_state(priv); | ||
1222 | |||
1223 | mutex_unlock(&xc5000_list_mutex); | ||
1224 | |||
1225 | fe->tuner_priv = NULL; | ||
1226 | |||
1227 | return 0; | ||
1228 | } | ||
1229 | |||
1230 | static int xc5000_set_config(struct dvb_frontend *fe, void *priv_cfg) | ||
1231 | { | ||
1232 | struct xc5000_priv *priv = fe->tuner_priv; | ||
1233 | struct xc5000_config *p = priv_cfg; | ||
1234 | |||
1235 | dprintk(1, "%s()\n", __func__); | ||
1236 | |||
1237 | if (p->if_khz) | ||
1238 | priv->if_khz = p->if_khz; | ||
1239 | |||
1240 | if (p->radio_input) | ||
1241 | priv->radio_input = p->radio_input; | ||
1242 | |||
1243 | return 0; | ||
1244 | } | ||
1245 | |||
1246 | |||
1247 | static const struct dvb_tuner_ops xc5000_tuner_ops = { | ||
1248 | .info = { | ||
1249 | .name = "Xceive XC5000", | ||
1250 | .frequency_min = 1000000, | ||
1251 | .frequency_max = 1023000000, | ||
1252 | .frequency_step = 50000, | ||
1253 | }, | ||
1254 | |||
1255 | .release = xc5000_release, | ||
1256 | .init = xc5000_init, | ||
1257 | .sleep = xc5000_sleep, | ||
1258 | |||
1259 | .set_config = xc5000_set_config, | ||
1260 | .set_params = xc5000_set_params, | ||
1261 | .set_analog_params = xc5000_set_analog_params, | ||
1262 | .get_frequency = xc5000_get_frequency, | ||
1263 | .get_if_frequency = xc5000_get_if_frequency, | ||
1264 | .get_bandwidth = xc5000_get_bandwidth, | ||
1265 | .get_status = xc5000_get_status | ||
1266 | }; | ||
1267 | |||
1268 | struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, | ||
1269 | struct i2c_adapter *i2c, | ||
1270 | const struct xc5000_config *cfg) | ||
1271 | { | ||
1272 | struct xc5000_priv *priv = NULL; | ||
1273 | int instance; | ||
1274 | u16 id = 0; | ||
1275 | |||
1276 | dprintk(1, "%s(%d-%04x)\n", __func__, | ||
1277 | i2c ? i2c_adapter_id(i2c) : -1, | ||
1278 | cfg ? cfg->i2c_address : -1); | ||
1279 | |||
1280 | mutex_lock(&xc5000_list_mutex); | ||
1281 | |||
1282 | instance = hybrid_tuner_request_state(struct xc5000_priv, priv, | ||
1283 | hybrid_tuner_instance_list, | ||
1284 | i2c, cfg->i2c_address, "xc5000"); | ||
1285 | switch (instance) { | ||
1286 | case 0: | ||
1287 | goto fail; | ||
1288 | break; | ||
1289 | case 1: | ||
1290 | /* new tuner instance */ | ||
1291 | priv->bandwidth = 6000000; | ||
1292 | fe->tuner_priv = priv; | ||
1293 | break; | ||
1294 | default: | ||
1295 | /* existing tuner instance */ | ||
1296 | fe->tuner_priv = priv; | ||
1297 | break; | ||
1298 | } | ||
1299 | |||
1300 | if (priv->if_khz == 0) { | ||
1301 | /* If the IF hasn't been set yet, use the value provided by | ||
1302 | the caller (occurs in hybrid devices where the analog | ||
1303 | call to xc5000_attach occurs before the digital side) */ | ||
1304 | priv->if_khz = cfg->if_khz; | ||
1305 | } | ||
1306 | |||
1307 | if (priv->xtal_khz == 0) | ||
1308 | priv->xtal_khz = cfg->xtal_khz; | ||
1309 | |||
1310 | if (priv->radio_input == 0) | ||
1311 | priv->radio_input = cfg->radio_input; | ||
1312 | |||
1313 | /* don't override chip id if it's already been set | ||
1314 | unless explicitly specified */ | ||
1315 | if ((priv->chip_id == 0) || (cfg->chip_id)) | ||
1316 | /* use default chip id if none specified, set to 0 so | ||
1317 | it can be overridden if this is a hybrid driver */ | ||
1318 | priv->chip_id = (cfg->chip_id) ? cfg->chip_id : 0; | ||
1319 | |||
1320 | /* Check if firmware has been loaded. It is possible that another | ||
1321 | instance of the driver has loaded the firmware. | ||
1322 | */ | ||
1323 | if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != XC_RESULT_SUCCESS) | ||
1324 | goto fail; | ||
1325 | |||
1326 | switch (id) { | ||
1327 | case XC_PRODUCT_ID_FW_LOADED: | ||
1328 | printk(KERN_INFO | ||
1329 | "xc5000: Successfully identified at address 0x%02x\n", | ||
1330 | cfg->i2c_address); | ||
1331 | printk(KERN_INFO | ||
1332 | "xc5000: Firmware has been loaded previously\n"); | ||
1333 | break; | ||
1334 | case XC_PRODUCT_ID_FW_NOT_LOADED: | ||
1335 | printk(KERN_INFO | ||
1336 | "xc5000: Successfully identified at address 0x%02x\n", | ||
1337 | cfg->i2c_address); | ||
1338 | printk(KERN_INFO | ||
1339 | "xc5000: Firmware has not been loaded previously\n"); | ||
1340 | break; | ||
1341 | default: | ||
1342 | printk(KERN_ERR | ||
1343 | "xc5000: Device not found at addr 0x%02x (0x%x)\n", | ||
1344 | cfg->i2c_address, id); | ||
1345 | goto fail; | ||
1346 | } | ||
1347 | |||
1348 | mutex_unlock(&xc5000_list_mutex); | ||
1349 | |||
1350 | memcpy(&fe->ops.tuner_ops, &xc5000_tuner_ops, | ||
1351 | sizeof(struct dvb_tuner_ops)); | ||
1352 | |||
1353 | return fe; | ||
1354 | fail: | ||
1355 | mutex_unlock(&xc5000_list_mutex); | ||
1356 | |||
1357 | xc5000_release(fe); | ||
1358 | return NULL; | ||
1359 | } | ||
1360 | EXPORT_SYMBOL(xc5000_attach); | ||
1361 | |||
1362 | MODULE_AUTHOR("Steven Toth"); | ||
1363 | MODULE_DESCRIPTION("Xceive xc5000 silicon tuner driver"); | ||
1364 | MODULE_LICENSE("GPL"); | ||
1365 | MODULE_FIRMWARE(XC5000A_FIRMWARE); | ||
1366 | MODULE_FIRMWARE(XC5000C_FIRMWARE); | ||
diff --git a/drivers/media/tuners/xc5000.h b/drivers/media/tuners/xc5000.h new file mode 100644 index 000000000000..b1a547494625 --- /dev/null +++ b/drivers/media/tuners/xc5000.h | |||
@@ -0,0 +1,74 @@ | |||
1 | /* | ||
2 | * Driver for Xceive XC5000 "QAM/8VSB single chip tuner" | ||
3 | * | ||
4 | * Copyright (c) 2007 Steven Toth <stoth@linuxtv.org> | ||
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 __XC5000_H__ | ||
23 | #define __XC5000_H__ | ||
24 | |||
25 | #include <linux/firmware.h> | ||
26 | |||
27 | struct dvb_frontend; | ||
28 | struct i2c_adapter; | ||
29 | |||
30 | #define XC5000A 1 | ||
31 | #define XC5000C 2 | ||
32 | |||
33 | struct xc5000_config { | ||
34 | u8 i2c_address; | ||
35 | u32 if_khz; | ||
36 | u8 radio_input; | ||
37 | u16 xtal_khz; | ||
38 | |||
39 | int chip_id; | ||
40 | }; | ||
41 | |||
42 | /* xc5000 callback command */ | ||
43 | #define XC5000_TUNER_RESET 0 | ||
44 | |||
45 | /* Possible Radio inputs */ | ||
46 | #define XC5000_RADIO_NOT_CONFIGURED 0 | ||
47 | #define XC5000_RADIO_FM1 1 | ||
48 | #define XC5000_RADIO_FM2 2 | ||
49 | #define XC5000_RADIO_FM1_MONO 3 | ||
50 | |||
51 | /* For each bridge framework, when it attaches either analog or digital, | ||
52 | * it has to store a reference back to its _core equivalent structure, | ||
53 | * so that it can service the hardware by steering gpio's etc. | ||
54 | * Each bridge implementation is different so cast devptr accordingly. | ||
55 | * The xc5000 driver cares not for this value, other than ensuring | ||
56 | * it's passed back to a bridge during tuner_callback(). | ||
57 | */ | ||
58 | |||
59 | #if defined(CONFIG_MEDIA_TUNER_XC5000) || \ | ||
60 | (defined(CONFIG_MEDIA_TUNER_XC5000_MODULE) && defined(MODULE)) | ||
61 | extern struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, | ||
62 | struct i2c_adapter *i2c, | ||
63 | const struct xc5000_config *cfg); | ||
64 | #else | ||
65 | static inline struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe, | ||
66 | struct i2c_adapter *i2c, | ||
67 | const struct xc5000_config *cfg) | ||
68 | { | ||
69 | printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); | ||
70 | return NULL; | ||
71 | } | ||
72 | #endif | ||
73 | |||
74 | #endif | ||