diff options
author | Antti Palosaari <crope@iki.fi> | 2011-04-09 19:07:30 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-05-20 08:26:57 -0400 |
commit | 26eb7045f1c9eee3b65f573d27154d53aa9d6cc7 (patch) | |
tree | 285fb3aee7db0617c2879f42ac2a9b359c78034f /drivers/media/common | |
parent | 437b77552fe24f934836b28074a87a32f6fe485a (diff) |
[media] NXP TDA18212HN silicon tuner driver
New silicon tuner driver.
Signed-off-by: Antti Palosaari <crope@iki.fi>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/common')
-rw-r--r-- | drivers/media/common/tuners/Kconfig | 8 | ||||
-rw-r--r-- | drivers/media/common/tuners/Makefile | 1 | ||||
-rw-r--r-- | drivers/media/common/tuners/tda18212.c | 265 | ||||
-rw-r--r-- | drivers/media/common/tuners/tda18212.h | 48 | ||||
-rw-r--r-- | drivers/media/common/tuners/tda18212_priv.h | 44 |
5 files changed, 366 insertions, 0 deletions
diff --git a/drivers/media/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig index 6fc79f15dcbc..22d3ca36370e 100644 --- a/drivers/media/common/tuners/Kconfig +++ b/drivers/media/common/tuners/Kconfig | |||
@@ -186,4 +186,12 @@ config MEDIA_TUNER_TDA18218 | |||
186 | default m if MEDIA_TUNER_CUSTOMISE | 186 | default m if MEDIA_TUNER_CUSTOMISE |
187 | help | 187 | help |
188 | NXP TDA18218 silicon tuner driver. | 188 | NXP TDA18218 silicon tuner driver. |
189 | |||
190 | config MEDIA_TUNER_TDA18212 | ||
191 | tristate "NXP TDA18212 silicon tuner" | ||
192 | depends on VIDEO_MEDIA && I2C | ||
193 | default m if MEDIA_TUNER_CUSTOMISE | ||
194 | help | ||
195 | NXP TDA18212 silicon tuner driver. | ||
196 | |||
189 | endmenu | 197 | endmenu |
diff --git a/drivers/media/common/tuners/Makefile b/drivers/media/common/tuners/Makefile index 96da03d349ca..2cb4f5327843 100644 --- a/drivers/media/common/tuners/Makefile +++ b/drivers/media/common/tuners/Makefile | |||
@@ -25,6 +25,7 @@ obj-$(CONFIG_MEDIA_TUNER_MXL5007T) += mxl5007t.o | |||
25 | obj-$(CONFIG_MEDIA_TUNER_MC44S803) += mc44s803.o | 25 | obj-$(CONFIG_MEDIA_TUNER_MC44S803) += mc44s803.o |
26 | obj-$(CONFIG_MEDIA_TUNER_MAX2165) += max2165.o | 26 | obj-$(CONFIG_MEDIA_TUNER_MAX2165) += max2165.o |
27 | obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o | 27 | obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o |
28 | obj-$(CONFIG_MEDIA_TUNER_TDA18212) += tda18212.o | ||
28 | 29 | ||
29 | EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core | 30 | EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core |
30 | EXTRA_CFLAGS += -Idrivers/media/dvb/frontends | 31 | EXTRA_CFLAGS += -Idrivers/media/dvb/frontends |
diff --git a/drivers/media/common/tuners/tda18212.c b/drivers/media/common/tuners/tda18212.c new file mode 100644 index 000000000000..1f1db20d46b1 --- /dev/null +++ b/drivers/media/common/tuners/tda18212.c | |||
@@ -0,0 +1,265 @@ | |||
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_priv.h" | ||
22 | |||
23 | static int debug; | ||
24 | module_param(debug, int, 0644); | ||
25 | MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); | ||
26 | |||
27 | /* write multiple registers */ | ||
28 | static int tda18212_wr_regs(struct tda18212_priv *priv, u8 reg, u8 *val, | ||
29 | int len) | ||
30 | { | ||
31 | int ret; | ||
32 | u8 buf[len+1]; | ||
33 | struct i2c_msg msg[1] = { | ||
34 | { | ||
35 | .addr = priv->cfg->i2c_address, | ||
36 | .flags = 0, | ||
37 | .len = sizeof(buf), | ||
38 | .buf = buf, | ||
39 | } | ||
40 | }; | ||
41 | |||
42 | buf[0] = reg; | ||
43 | memcpy(&buf[1], val, len); | ||
44 | |||
45 | ret = i2c_transfer(priv->i2c, msg, 1); | ||
46 | if (ret == 1) { | ||
47 | ret = 0; | ||
48 | } else { | ||
49 | warn("i2c wr failed ret:%d reg:%02x len:%d", ret, reg, len); | ||
50 | ret = -EREMOTEIO; | ||
51 | } | ||
52 | return ret; | ||
53 | } | ||
54 | |||
55 | /* read multiple registers */ | ||
56 | static int tda18212_rd_regs(struct tda18212_priv *priv, u8 reg, u8 *val, | ||
57 | int len) | ||
58 | { | ||
59 | int ret; | ||
60 | u8 buf[len]; | ||
61 | struct i2c_msg msg[2] = { | ||
62 | { | ||
63 | .addr = priv->cfg->i2c_address, | ||
64 | .flags = 0, | ||
65 | .len = 1, | ||
66 | .buf = ®, | ||
67 | }, { | ||
68 | .addr = priv->cfg->i2c_address, | ||
69 | .flags = I2C_M_RD, | ||
70 | .len = sizeof(buf), | ||
71 | .buf = buf, | ||
72 | } | ||
73 | }; | ||
74 | |||
75 | ret = i2c_transfer(priv->i2c, msg, 2); | ||
76 | if (ret == 2) { | ||
77 | memcpy(val, buf, len); | ||
78 | ret = 0; | ||
79 | } else { | ||
80 | warn("i2c rd failed ret:%d reg:%02x len:%d", ret, reg, len); | ||
81 | ret = -EREMOTEIO; | ||
82 | } | ||
83 | |||
84 | return ret; | ||
85 | } | ||
86 | |||
87 | /* write single register */ | ||
88 | static int tda18212_wr_reg(struct tda18212_priv *priv, u8 reg, u8 val) | ||
89 | { | ||
90 | return tda18212_wr_regs(priv, reg, &val, 1); | ||
91 | } | ||
92 | |||
93 | /* read single register */ | ||
94 | static int tda18212_rd_reg(struct tda18212_priv *priv, u8 reg, u8 *val) | ||
95 | { | ||
96 | return tda18212_rd_regs(priv, reg, val, 1); | ||
97 | } | ||
98 | |||
99 | #if 0 /* keep, useful when developing driver */ | ||
100 | static void tda18212_dump_regs(struct tda18212_priv *priv) | ||
101 | { | ||
102 | int i; | ||
103 | u8 buf[256]; | ||
104 | |||
105 | #define TDA18212_RD_LEN 32 | ||
106 | for (i = 0; i < sizeof(buf); i += TDA18212_RD_LEN) | ||
107 | tda18212_rd_regs(priv, i, &buf[i], TDA18212_RD_LEN); | ||
108 | |||
109 | print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 32, 1, buf, | ||
110 | sizeof(buf), true); | ||
111 | |||
112 | return; | ||
113 | } | ||
114 | #endif | ||
115 | |||
116 | static int tda18212_set_params(struct dvb_frontend *fe, | ||
117 | struct dvb_frontend_parameters *p) | ||
118 | { | ||
119 | struct tda18212_priv *priv = fe->tuner_priv; | ||
120 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
121 | int ret, i; | ||
122 | u32 if_khz; | ||
123 | u8 buf[9]; | ||
124 | static const u8 bw_params[][3] = { | ||
125 | /* 0f 13 23 */ | ||
126 | { 0xb3, 0x20, 0x03 }, /* DVB-T 6 MHz */ | ||
127 | { 0xb3, 0x31, 0x01 }, /* DVB-T 7 MHz */ | ||
128 | { 0xb3, 0x22, 0x01 }, /* DVB-T 8 MHz */ | ||
129 | { 0x92, 0x53, 0x03 }, /* DVB-C */ | ||
130 | }; | ||
131 | |||
132 | dbg("%s: delsys=%d RF=%d BW=%d", __func__, | ||
133 | c->delivery_system, c->frequency, c->bandwidth_hz); | ||
134 | |||
135 | if (fe->ops.i2c_gate_ctrl) | ||
136 | fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ | ||
137 | |||
138 | switch (c->delivery_system) { | ||
139 | case SYS_DVBT: | ||
140 | switch (c->bandwidth_hz) { | ||
141 | case 6000000: | ||
142 | if_khz = priv->cfg->if_dvbt_6; | ||
143 | i = 0; | ||
144 | break; | ||
145 | case 7000000: | ||
146 | if_khz = priv->cfg->if_dvbt_7; | ||
147 | i = 1; | ||
148 | break; | ||
149 | case 8000000: | ||
150 | if_khz = priv->cfg->if_dvbt_8; | ||
151 | i = 2; | ||
152 | break; | ||
153 | default: | ||
154 | ret = -EINVAL; | ||
155 | goto error; | ||
156 | } | ||
157 | break; | ||
158 | case SYS_DVBC_ANNEX_AC: | ||
159 | if_khz = priv->cfg->if_dvbc; | ||
160 | i = 3; | ||
161 | break; | ||
162 | default: | ||
163 | ret = -EINVAL; | ||
164 | goto error; | ||
165 | } | ||
166 | |||
167 | ret = tda18212_wr_reg(priv, 0x23, bw_params[i][2]); | ||
168 | if (ret) | ||
169 | goto error; | ||
170 | |||
171 | ret = tda18212_wr_reg(priv, 0x06, 0x00); | ||
172 | if (ret) | ||
173 | goto error; | ||
174 | |||
175 | ret = tda18212_wr_reg(priv, 0x0f, bw_params[i][0]); | ||
176 | if (ret) | ||
177 | goto error; | ||
178 | |||
179 | buf[0] = 0x02; | ||
180 | buf[1] = bw_params[i][1]; | ||
181 | buf[2] = 0x03; /* default value */ | ||
182 | buf[3] = if_khz / 50; | ||
183 | buf[4] = ((c->frequency / 1000) >> 16) & 0xff; | ||
184 | buf[5] = ((c->frequency / 1000) >> 8) & 0xff; | ||
185 | buf[6] = ((c->frequency / 1000) >> 0) & 0xff; | ||
186 | buf[7] = 0xc1; | ||
187 | buf[8] = 0x01; | ||
188 | ret = tda18212_wr_regs(priv, 0x12, buf, sizeof(buf)); | ||
189 | if (ret) | ||
190 | goto error; | ||
191 | |||
192 | exit: | ||
193 | if (fe->ops.i2c_gate_ctrl) | ||
194 | fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ | ||
195 | |||
196 | return ret; | ||
197 | |||
198 | error: | ||
199 | dbg("%s: failed:%d", __func__, ret); | ||
200 | goto exit; | ||
201 | } | ||
202 | |||
203 | static int tda18212_release(struct dvb_frontend *fe) | ||
204 | { | ||
205 | kfree(fe->tuner_priv); | ||
206 | fe->tuner_priv = NULL; | ||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | static const struct dvb_tuner_ops tda18212_tuner_ops = { | ||
211 | .info = { | ||
212 | .name = "NXP TDA18212", | ||
213 | |||
214 | .frequency_min = 48000000, | ||
215 | .frequency_max = 864000000, | ||
216 | .frequency_step = 1000, | ||
217 | }, | ||
218 | |||
219 | .release = tda18212_release, | ||
220 | |||
221 | .set_params = tda18212_set_params, | ||
222 | }; | ||
223 | |||
224 | struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe, | ||
225 | struct i2c_adapter *i2c, struct tda18212_config *cfg) | ||
226 | { | ||
227 | struct tda18212_priv *priv = NULL; | ||
228 | int ret; | ||
229 | u8 val; | ||
230 | |||
231 | priv = kzalloc(sizeof(struct tda18212_priv), GFP_KERNEL); | ||
232 | if (priv == NULL) | ||
233 | return NULL; | ||
234 | |||
235 | priv->cfg = cfg; | ||
236 | priv->i2c = i2c; | ||
237 | fe->tuner_priv = priv; | ||
238 | |||
239 | if (fe->ops.i2c_gate_ctrl) | ||
240 | fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */ | ||
241 | |||
242 | /* check if the tuner is there */ | ||
243 | ret = tda18212_rd_reg(priv, 0x00, &val); | ||
244 | |||
245 | if (fe->ops.i2c_gate_ctrl) | ||
246 | fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */ | ||
247 | |||
248 | dbg("%s: ret:%d chip ID:%02x", __func__, ret, val); | ||
249 | if (ret || val != 0xc7) { | ||
250 | kfree(priv); | ||
251 | return NULL; | ||
252 | } | ||
253 | |||
254 | info("NXP TDA18212HN successfully identified."); | ||
255 | |||
256 | memcpy(&fe->ops.tuner_ops, &tda18212_tuner_ops, | ||
257 | sizeof(struct dvb_tuner_ops)); | ||
258 | |||
259 | return fe; | ||
260 | } | ||
261 | EXPORT_SYMBOL(tda18212_attach); | ||
262 | |||
263 | MODULE_DESCRIPTION("NXP TDA18212HN silicon tuner driver"); | ||
264 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | ||
265 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/common/tuners/tda18212.h b/drivers/media/common/tuners/tda18212.h new file mode 100644 index 000000000000..83b497f59e1b --- /dev/null +++ b/drivers/media/common/tuners/tda18212.h | |||
@@ -0,0 +1,48 @@ | |||
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_dvbc; | ||
33 | }; | ||
34 | |||
35 | #if defined(CONFIG_MEDIA_TUNER_TDA18212) || \ | ||
36 | (defined(CONFIG_MEDIA_TUNER_TDA18212_MODULE) && defined(MODULE)) | ||
37 | extern struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe, | ||
38 | struct i2c_adapter *i2c, struct tda18212_config *cfg); | ||
39 | #else | ||
40 | static inline struct dvb_frontend *tda18212_attach(struct dvb_frontend *fe, | ||
41 | struct i2c_adapter *i2c, struct tda18212_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/common/tuners/tda18212_priv.h b/drivers/media/common/tuners/tda18212_priv.h new file mode 100644 index 000000000000..9adff9356b73 --- /dev/null +++ b/drivers/media/common/tuners/tda18212_priv.h | |||
@@ -0,0 +1,44 @@ | |||
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_PRIV_H | ||
22 | #define TDA18212_PRIV_H | ||
23 | |||
24 | #include "tda18212.h" | ||
25 | |||
26 | #define LOG_PREFIX "tda18212" | ||
27 | |||
28 | #undef dbg | ||
29 | #define dbg(f, arg...) \ | ||
30 | if (debug) \ | ||
31 | printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) | ||
32 | #undef err | ||
33 | #define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg) | ||
34 | #undef info | ||
35 | #define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg) | ||
36 | #undef warn | ||
37 | #define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg) | ||
38 | |||
39 | struct tda18212_priv { | ||
40 | struct tda18212_config *cfg; | ||
41 | struct i2c_adapter *i2c; | ||
42 | }; | ||
43 | |||
44 | #endif | ||