blob: 6147eeef4a6661ee3210caa915bdd8375e681a1c [file] [log] [blame]
Antti Palosaarif9263742012-03-30 06:37:26 -03001/*
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 */
25static 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
50static int tua9001_release(struct dvb_frontend *fe)
51{
Antti Palosaari89054e32012-09-11 22:27:07 -030052 struct tua9001_priv *priv = fe->tuner_priv;
53 int ret = 0;
54
55 if (fe->callback)
56 ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
57 TUA9001_CMD_CEN, 0);
58
Antti Palosaarif9263742012-03-30 06:37:26 -030059 kfree(fe->tuner_priv);
60 fe->tuner_priv = NULL;
61
Antti Palosaari89054e32012-09-11 22:27:07 -030062 return ret;
Antti Palosaarif9263742012-03-30 06:37:26 -030063}
64
65static int tua9001_init(struct dvb_frontend *fe)
66{
67 struct tua9001_priv *priv = fe->tuner_priv;
68 int ret = 0;
69 u8 i;
70 struct reg_val data[] = {
71 { 0x1e, 0x6512 },
72 { 0x25, 0xb888 },
73 { 0x39, 0x5460 },
74 { 0x3b, 0x00c0 },
75 { 0x3a, 0xf000 },
76 { 0x08, 0x0000 },
77 { 0x32, 0x0030 },
78 { 0x41, 0x703a },
79 { 0x40, 0x1c78 },
80 { 0x2c, 0x1c00 },
81 { 0x36, 0xc013 },
82 { 0x37, 0x6f18 },
83 { 0x27, 0x0008 },
84 { 0x2a, 0x0001 },
85 { 0x34, 0x0a40 },
86 };
87
Antti Palosaari89054e32012-09-11 22:27:07 -030088 if (fe->callback) {
89 ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
90 TUA9001_CMD_RESETN, 0);
91 if (ret < 0)
92 goto err;
93 }
94
Antti Palosaarif9263742012-03-30 06:37:26 -030095 if (fe->ops.i2c_gate_ctrl)
96 fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c-gate */
97
98 for (i = 0; i < ARRAY_SIZE(data); i++) {
99 ret = tua9001_wr_reg(priv, data[i].reg, data[i].val);
Antti Palosaari89054e32012-09-11 22:27:07 -0300100 if (ret < 0)
101 goto err_i2c_gate_ctrl;
Antti Palosaarif9263742012-03-30 06:37:26 -0300102 }
103
Antti Palosaari89054e32012-09-11 22:27:07 -0300104err_i2c_gate_ctrl:
Antti Palosaarif9263742012-03-30 06:37:26 -0300105 if (fe->ops.i2c_gate_ctrl)
106 fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c-gate */
Antti Palosaari89054e32012-09-11 22:27:07 -0300107err:
108 if (ret < 0)
109 pr_debug("%s: failed=%d\n", __func__, ret);
110
111 return ret;
112}
113
114static int tua9001_sleep(struct dvb_frontend *fe)
115{
116 struct tua9001_priv *priv = fe->tuner_priv;
117 int ret = 0;
118
119 if (fe->callback)
120 ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
121 TUA9001_CMD_RESETN, 1);
Antti Palosaarif9263742012-03-30 06:37:26 -0300122
123 if (ret < 0)
124 pr_debug("%s: failed=%d\n", __func__, ret);
125
126 return ret;
127}
128
129static int tua9001_set_params(struct dvb_frontend *fe)
130{
131 struct tua9001_priv *priv = fe->tuner_priv;
132 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
133 int ret, i;
134 u16 val;
135 u32 frequency;
136 struct reg_val data[2];
137
138 pr_debug("%s: delivery_system=%d frequency=%d bandwidth_hz=%d\n",
139 __func__, c->delivery_system, c->frequency,
140 c->bandwidth_hz);
141
142 switch (c->delivery_system) {
143 case SYS_DVBT:
144 switch (c->bandwidth_hz) {
145 case 8000000:
146 val = 0x0000;
147 break;
148 case 7000000:
149 val = 0x1000;
150 break;
151 case 6000000:
152 val = 0x2000;
153 break;
154 case 5000000:
155 val = 0x3000;
156 break;
157 default:
158 ret = -EINVAL;
159 goto err;
160 }
161 break;
162 default:
163 ret = -EINVAL;
164 goto err;
165 }
166
167 data[0].reg = 0x04;
168 data[0].val = val;
169
170 frequency = (c->frequency - 150000000);
171 frequency /= 100;
172 frequency *= 48;
173 frequency /= 10000;
174
175 data[1].reg = 0x1f;
176 data[1].val = frequency;
177
178 if (fe->ops.i2c_gate_ctrl)
179 fe->ops.i2c_gate_ctrl(fe, 1); /* open i2c-gate */
180
Antti Palosaari89054e32012-09-11 22:27:07 -0300181 if (fe->callback) {
182 ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
183 TUA9001_CMD_RXEN, 0);
184 if (ret < 0)
185 goto err_i2c_gate_ctrl;
186 }
187
Antti Palosaarif9263742012-03-30 06:37:26 -0300188 for (i = 0; i < ARRAY_SIZE(data); i++) {
189 ret = tua9001_wr_reg(priv, data[i].reg, data[i].val);
190 if (ret < 0)
Antti Palosaari89054e32012-09-11 22:27:07 -0300191 goto err_i2c_gate_ctrl;
Antti Palosaarif9263742012-03-30 06:37:26 -0300192 }
193
Antti Palosaari89054e32012-09-11 22:27:07 -0300194 if (fe->callback) {
195 ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
196 TUA9001_CMD_RXEN, 1);
197 if (ret < 0)
198 goto err_i2c_gate_ctrl;
199 }
200
201err_i2c_gate_ctrl:
Antti Palosaarif9263742012-03-30 06:37:26 -0300202 if (fe->ops.i2c_gate_ctrl)
203 fe->ops.i2c_gate_ctrl(fe, 0); /* close i2c-gate */
Antti Palosaarif9263742012-03-30 06:37:26 -0300204err:
205 if (ret < 0)
206 pr_debug("%s: failed=%d\n", __func__, ret);
207
208 return ret;
209}
210
211static int tua9001_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
212{
213 *frequency = 0; /* Zero-IF */
214
215 return 0;
216}
217
218static const struct dvb_tuner_ops tua9001_tuner_ops = {
219 .info = {
220 .name = "Infineon TUA 9001",
221
222 .frequency_min = 170000000,
223 .frequency_max = 862000000,
224 .frequency_step = 0,
225 },
226
227 .release = tua9001_release,
228
229 .init = tua9001_init,
Antti Palosaari89054e32012-09-11 22:27:07 -0300230 .sleep = tua9001_sleep,
Antti Palosaarif9263742012-03-30 06:37:26 -0300231 .set_params = tua9001_set_params,
232
233 .get_if_frequency = tua9001_get_if_frequency,
234};
235
236struct dvb_frontend *tua9001_attach(struct dvb_frontend *fe,
237 struct i2c_adapter *i2c, struct tua9001_config *cfg)
238{
239 struct tua9001_priv *priv = NULL;
Antti Palosaari89054e32012-09-11 22:27:07 -0300240 int ret;
Antti Palosaarif9263742012-03-30 06:37:26 -0300241
242 priv = kzalloc(sizeof(struct tua9001_priv), GFP_KERNEL);
243 if (priv == NULL)
244 return NULL;
245
246 priv->cfg = cfg;
247 priv->i2c = i2c;
248
Antti Palosaari89054e32012-09-11 22:27:07 -0300249 if (fe->callback) {
250 ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
251 TUA9001_CMD_CEN, 1);
252 if (ret < 0)
253 goto err;
254 }
255
Antti Palosaarif9263742012-03-30 06:37:26 -0300256 printk(KERN_INFO "Infineon TUA 9001 successfully attached.");
257
258 memcpy(&fe->ops.tuner_ops, &tua9001_tuner_ops,
259 sizeof(struct dvb_tuner_ops));
260
261 fe->tuner_priv = priv;
262 return fe;
Antti Palosaari89054e32012-09-11 22:27:07 -0300263err:
264 kfree(priv);
265 return NULL;
Antti Palosaarif9263742012-03-30 06:37:26 -0300266}
267EXPORT_SYMBOL(tua9001_attach);
268
269MODULE_DESCRIPTION("Infineon TUA 9001 silicon tuner driver");
270MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
271MODULE_LICENSE("GPL");