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