blob: de2607084672f813287a40bb7a916aea5a0403fe [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{
52 kfree(fe->tuner_priv);
53 fe->tuner_priv = NULL;
54
55 return 0;
56}
57
58static 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
99static 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
160err:
161 if (ret < 0)
162 pr_debug("%s: failed=%d\n", __func__, ret);
163
164 return ret;
165}
166
167static int tua9001_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
168{
169 *frequency = 0; /* Zero-IF */
170
171 return 0;
172}
173
174static 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
191struct 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}
211EXPORT_SYMBOL(tua9001_attach);
212
213MODULE_DESCRIPTION("Infineon TUA 9001 silicon tuner driver");
214MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
215MODULE_LICENSE("GPL");