]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Infineon TUA9001 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 | ||
17 | #include "tua9001_priv.h" | |
18 | ||
19 | static int tua9001_init(struct dvb_frontend *fe) | |
20 | { | |
21 | struct tua9001_dev *dev = fe->tuner_priv; | |
22 | struct i2c_client *client = dev->client; | |
23 | int ret, i; | |
24 | static const struct tua9001_reg_val data[] = { | |
25 | {0x1e, 0x6512}, | |
26 | {0x25, 0xb888}, | |
27 | {0x39, 0x5460}, | |
28 | {0x3b, 0x00c0}, | |
29 | {0x3a, 0xf000}, | |
30 | {0x08, 0x0000}, | |
31 | {0x32, 0x0030}, | |
32 | {0x41, 0x703a}, | |
33 | {0x40, 0x1c78}, | |
34 | {0x2c, 0x1c00}, | |
35 | {0x36, 0xc013}, | |
36 | {0x37, 0x6f18}, | |
37 | {0x27, 0x0008}, | |
38 | {0x2a, 0x0001}, | |
39 | {0x34, 0x0a40}, | |
40 | }; | |
41 | ||
42 | dev_dbg(&client->dev, "\n"); | |
43 | ||
44 | if (fe->callback) { | |
45 | ret = fe->callback(client->adapter, | |
46 | DVB_FRONTEND_COMPONENT_TUNER, | |
47 | TUA9001_CMD_RESETN, 0); | |
48 | if (ret) | |
49 | goto err; | |
50 | } | |
51 | ||
52 | for (i = 0; i < ARRAY_SIZE(data); i++) { | |
53 | ret = regmap_write(dev->regmap, data[i].reg, data[i].val); | |
54 | if (ret) | |
55 | goto err; | |
56 | } | |
57 | return 0; | |
58 | err: | |
59 | dev_dbg(&client->dev, "failed=%d\n", ret); | |
60 | return ret; | |
61 | } | |
62 | ||
63 | static int tua9001_sleep(struct dvb_frontend *fe) | |
64 | { | |
65 | struct tua9001_dev *dev = fe->tuner_priv; | |
66 | struct i2c_client *client = dev->client; | |
67 | int ret; | |
68 | ||
69 | dev_dbg(&client->dev, "\n"); | |
70 | ||
71 | if (fe->callback) { | |
72 | ret = fe->callback(client->adapter, | |
73 | DVB_FRONTEND_COMPONENT_TUNER, | |
74 | TUA9001_CMD_RESETN, 1); | |
75 | if (ret) | |
76 | goto err; | |
77 | } | |
78 | return 0; | |
79 | err: | |
80 | dev_dbg(&client->dev, "failed=%d\n", ret); | |
81 | return ret; | |
82 | } | |
83 | ||
84 | static int tua9001_set_params(struct dvb_frontend *fe) | |
85 | { | |
86 | struct tua9001_dev *dev = fe->tuner_priv; | |
87 | struct i2c_client *client = dev->client; | |
88 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | |
89 | int ret, i; | |
90 | u16 val; | |
91 | u32 frequency; | |
92 | struct tua9001_reg_val data[2]; | |
93 | ||
94 | dev_dbg(&client->dev, | |
95 | "delivery_system=%u frequency=%u bandwidth_hz=%u\n", | |
96 | c->delivery_system, c->frequency, c->bandwidth_hz); | |
97 | ||
98 | switch (c->delivery_system) { | |
99 | case SYS_DVBT: | |
100 | switch (c->bandwidth_hz) { | |
101 | case 8000000: | |
102 | val = 0x0000; | |
103 | break; | |
104 | case 7000000: | |
105 | val = 0x1000; | |
106 | break; | |
107 | case 6000000: | |
108 | val = 0x2000; | |
109 | break; | |
110 | case 5000000: | |
111 | val = 0x3000; | |
112 | break; | |
113 | default: | |
114 | ret = -EINVAL; | |
115 | goto err; | |
116 | } | |
117 | break; | |
118 | default: | |
119 | ret = -EINVAL; | |
120 | goto err; | |
121 | } | |
122 | ||
123 | data[0].reg = 0x04; | |
124 | data[0].val = val; | |
125 | ||
126 | frequency = (c->frequency - 150000000); | |
127 | frequency /= 100; | |
128 | frequency *= 48; | |
129 | frequency /= 10000; | |
130 | ||
131 | data[1].reg = 0x1f; | |
132 | data[1].val = frequency; | |
133 | ||
134 | if (fe->callback) { | |
135 | ret = fe->callback(client->adapter, | |
136 | DVB_FRONTEND_COMPONENT_TUNER, | |
137 | TUA9001_CMD_RXEN, 0); | |
138 | if (ret) | |
139 | goto err; | |
140 | } | |
141 | ||
142 | for (i = 0; i < ARRAY_SIZE(data); i++) { | |
143 | ret = regmap_write(dev->regmap, data[i].reg, data[i].val); | |
144 | if (ret) | |
145 | goto err; | |
146 | } | |
147 | ||
148 | if (fe->callback) { | |
149 | ret = fe->callback(client->adapter, | |
150 | DVB_FRONTEND_COMPONENT_TUNER, | |
151 | TUA9001_CMD_RXEN, 1); | |
152 | if (ret) | |
153 | goto err; | |
154 | } | |
155 | return 0; | |
156 | err: | |
157 | dev_dbg(&client->dev, "failed=%d\n", ret); | |
158 | return ret; | |
159 | } | |
160 | ||
161 | static int tua9001_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) | |
162 | { | |
163 | struct tua9001_dev *dev = fe->tuner_priv; | |
164 | struct i2c_client *client = dev->client; | |
165 | ||
166 | dev_dbg(&client->dev, "\n"); | |
167 | ||
168 | *frequency = 0; /* Zero-IF */ | |
169 | return 0; | |
170 | } | |
171 | ||
172 | static const struct dvb_tuner_ops tua9001_tuner_ops = { | |
173 | .info = { | |
174 | .name = "Infineon TUA9001", | |
175 | .frequency_min = 170000000, | |
176 | .frequency_max = 862000000, | |
177 | }, | |
178 | ||
179 | .init = tua9001_init, | |
180 | .sleep = tua9001_sleep, | |
181 | .set_params = tua9001_set_params, | |
182 | ||
183 | .get_if_frequency = tua9001_get_if_frequency, | |
184 | }; | |
185 | ||
186 | static int tua9001_probe(struct i2c_client *client, | |
187 | const struct i2c_device_id *id) | |
188 | { | |
189 | struct tua9001_dev *dev; | |
190 | struct tua9001_platform_data *pdata = client->dev.platform_data; | |
191 | struct dvb_frontend *fe = pdata->dvb_frontend; | |
192 | int ret; | |
193 | static const struct regmap_config regmap_config = { | |
194 | .reg_bits = 8, | |
195 | .val_bits = 16, | |
196 | }; | |
197 | ||
198 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | |
199 | if (!dev) { | |
200 | ret = -ENOMEM; | |
201 | goto err; | |
202 | } | |
203 | ||
204 | dev->fe = pdata->dvb_frontend; | |
205 | dev->client = client; | |
206 | dev->regmap = devm_regmap_init_i2c(client, ®map_config); | |
207 | if (IS_ERR(dev->regmap)) { | |
208 | ret = PTR_ERR(dev->regmap); | |
209 | goto err_kfree; | |
210 | } | |
211 | ||
212 | if (fe->callback) { | |
213 | ret = fe->callback(client->adapter, | |
214 | DVB_FRONTEND_COMPONENT_TUNER, | |
215 | TUA9001_CMD_CEN, 1); | |
216 | if (ret) | |
217 | goto err_kfree; | |
218 | ||
219 | ret = fe->callback(client->adapter, | |
220 | DVB_FRONTEND_COMPONENT_TUNER, | |
221 | TUA9001_CMD_RXEN, 0); | |
222 | if (ret) | |
223 | goto err_kfree; | |
224 | ||
225 | ret = fe->callback(client->adapter, | |
226 | DVB_FRONTEND_COMPONENT_TUNER, | |
227 | TUA9001_CMD_RESETN, 1); | |
228 | if (ret) | |
229 | goto err_kfree; | |
230 | } | |
231 | ||
232 | fe->tuner_priv = dev; | |
233 | memcpy(&fe->ops.tuner_ops, &tua9001_tuner_ops, | |
234 | sizeof(struct dvb_tuner_ops)); | |
235 | i2c_set_clientdata(client, dev); | |
236 | ||
237 | dev_info(&client->dev, "Infineon TUA9001 successfully attached\n"); | |
238 | return 0; | |
239 | err_kfree: | |
240 | kfree(dev); | |
241 | err: | |
242 | dev_dbg(&client->dev, "failed=%d\n", ret); | |
243 | return ret; | |
244 | } | |
245 | ||
246 | static int tua9001_remove(struct i2c_client *client) | |
247 | { | |
248 | struct tua9001_dev *dev = i2c_get_clientdata(client); | |
249 | struct dvb_frontend *fe = dev->fe; | |
250 | int ret; | |
251 | ||
252 | dev_dbg(&client->dev, "\n"); | |
253 | ||
254 | if (fe->callback) { | |
255 | ret = fe->callback(client->adapter, | |
256 | DVB_FRONTEND_COMPONENT_TUNER, | |
257 | TUA9001_CMD_CEN, 0); | |
258 | if (ret) | |
259 | goto err_kfree; | |
260 | } | |
261 | kfree(dev); | |
262 | return 0; | |
263 | err_kfree: | |
264 | kfree(dev); | |
265 | dev_dbg(&client->dev, "failed=%d\n", ret); | |
266 | return ret; | |
267 | } | |
268 | ||
269 | static const struct i2c_device_id tua9001_id_table[] = { | |
270 | {"tua9001", 0}, | |
271 | {} | |
272 | }; | |
273 | MODULE_DEVICE_TABLE(i2c, tua9001_id_table); | |
274 | ||
275 | static struct i2c_driver tua9001_driver = { | |
276 | .driver = { | |
277 | .owner = THIS_MODULE, | |
278 | .name = "tua9001", | |
279 | .suppress_bind_attrs = true, | |
280 | }, | |
281 | .probe = tua9001_probe, | |
282 | .remove = tua9001_remove, | |
283 | .id_table = tua9001_id_table, | |
284 | }; | |
285 | ||
286 | module_i2c_driver(tua9001_driver); | |
287 | ||
288 | MODULE_DESCRIPTION("Infineon TUA9001 silicon tuner driver"); | |
289 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | |
290 | MODULE_LICENSE("GPL"); |