diff options
author | Antti Palosaari <crope@iki.fi> | 2014-11-11 22:01:44 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@osg.samsung.com> | 2014-11-14 14:22:34 -0500 |
commit | c867b265b15c2703fe07adcce064a2e3ba77ed13 (patch) | |
tree | 9e182ae990e01bb0b90e9dc237e0ef2971352c2d /drivers/staging | |
parent | 5048907076ea8b31aa15a3ec7a6ce9c341eb77ce (diff) |
[media] mn88472: move to staging
It is not ready enough to be released on mainline.
Signed-off-by: Antti Palosaari <crope@iki.fi>
Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
Diffstat (limited to 'drivers/staging')
-rw-r--r-- | drivers/staging/media/Kconfig | 2 | ||||
-rw-r--r-- | drivers/staging/media/Makefile | 1 | ||||
-rw-r--r-- | drivers/staging/media/mn88472/Kconfig | 7 | ||||
-rw-r--r-- | drivers/staging/media/mn88472/Makefile | 5 | ||||
-rw-r--r-- | drivers/staging/media/mn88472/mn88472.c | 523 | ||||
-rw-r--r-- | drivers/staging/media/mn88472/mn88472_priv.h | 36 |
6 files changed, 574 insertions, 0 deletions
diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig index 655cf5037b0b..c2e675aa22c5 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig | |||
@@ -27,6 +27,8 @@ source "drivers/staging/media/davinci_vpfe/Kconfig" | |||
27 | 27 | ||
28 | source "drivers/staging/media/dt3155v4l/Kconfig" | 28 | source "drivers/staging/media/dt3155v4l/Kconfig" |
29 | 29 | ||
30 | source "drivers/staging/media/mn88472/Kconfig" | ||
31 | |||
30 | source "drivers/staging/media/omap24xx/Kconfig" | 32 | source "drivers/staging/media/omap24xx/Kconfig" |
31 | 33 | ||
32 | source "drivers/staging/media/omap4iss/Kconfig" | 34 | source "drivers/staging/media/omap4iss/Kconfig" |
diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile index 6dbe578178cd..e174c57331e1 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile | |||
@@ -6,4 +6,5 @@ obj-$(CONFIG_VIDEO_DM365_VPFE) += davinci_vpfe/ | |||
6 | obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/ | 6 | obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/ |
7 | obj-$(CONFIG_VIDEO_OMAP2) += omap24xx/ | 7 | obj-$(CONFIG_VIDEO_OMAP2) += omap24xx/ |
8 | obj-$(CONFIG_VIDEO_TCM825X) += omap24xx/ | 8 | obj-$(CONFIG_VIDEO_TCM825X) += omap24xx/ |
9 | obj-$(CONFIG_DVB_MN88472) += mn88472/ | ||
9 | 10 | ||
diff --git a/drivers/staging/media/mn88472/Kconfig b/drivers/staging/media/mn88472/Kconfig new file mode 100644 index 000000000000..a85c90a60bce --- /dev/null +++ b/drivers/staging/media/mn88472/Kconfig | |||
@@ -0,0 +1,7 @@ | |||
1 | config DVB_MN88472 | ||
2 | tristate "Panasonic MN88472" | ||
3 | depends on DVB_CORE && I2C | ||
4 | select REGMAP_I2C | ||
5 | default m if !MEDIA_SUBDRV_AUTOSELECT | ||
6 | help | ||
7 | Say Y when you want to support this frontend. | ||
diff --git a/drivers/staging/media/mn88472/Makefile b/drivers/staging/media/mn88472/Makefile new file mode 100644 index 000000000000..5987b7e6d82a --- /dev/null +++ b/drivers/staging/media/mn88472/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | obj-$(CONFIG_DVB_MN88472) += mn88472.o | ||
2 | |||
3 | ccflags-y += -Idrivers/media/dvb-core/ | ||
4 | ccflags-y += -Idrivers/media/dvb-frontends/ | ||
5 | ccflags-y += -Idrivers/media/tuners/ | ||
diff --git a/drivers/staging/media/mn88472/mn88472.c b/drivers/staging/media/mn88472/mn88472.c new file mode 100644 index 000000000000..52de8f85d36c --- /dev/null +++ b/drivers/staging/media/mn88472/mn88472.c | |||
@@ -0,0 +1,523 @@ | |||
1 | /* | ||
2 | * Panasonic MN88472 DVB-T/T2/C demodulator driver | ||
3 | * | ||
4 | * Copyright (C) 2013 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 "mn88472_priv.h" | ||
18 | |||
19 | static int mn88472_get_tune_settings(struct dvb_frontend *fe, | ||
20 | struct dvb_frontend_tune_settings *s) | ||
21 | { | ||
22 | s->min_delay_ms = 400; | ||
23 | return 0; | ||
24 | } | ||
25 | |||
26 | static int mn88472_set_frontend(struct dvb_frontend *fe) | ||
27 | { | ||
28 | struct i2c_client *client = fe->demodulator_priv; | ||
29 | struct mn88472_dev *dev = i2c_get_clientdata(client); | ||
30 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
31 | int ret, i; | ||
32 | u32 if_frequency = 0; | ||
33 | u8 delivery_system_val, if_val[3], bw_val[7], bw_val2; | ||
34 | |||
35 | dev_dbg(&client->dev, | ||
36 | "delivery_system=%d modulation=%d frequency=%d symbol_rate=%d inversion=%d\n", | ||
37 | c->delivery_system, c->modulation, | ||
38 | c->frequency, c->symbol_rate, c->inversion); | ||
39 | |||
40 | if (!dev->warm) { | ||
41 | ret = -EAGAIN; | ||
42 | goto err; | ||
43 | } | ||
44 | |||
45 | switch (c->delivery_system) { | ||
46 | case SYS_DVBT: | ||
47 | delivery_system_val = 0x02; | ||
48 | break; | ||
49 | case SYS_DVBT2: | ||
50 | delivery_system_val = 0x03; | ||
51 | break; | ||
52 | case SYS_DVBC_ANNEX_A: | ||
53 | delivery_system_val = 0x04; | ||
54 | break; | ||
55 | default: | ||
56 | ret = -EINVAL; | ||
57 | goto err; | ||
58 | } | ||
59 | |||
60 | switch (c->delivery_system) { | ||
61 | case SYS_DVBT: | ||
62 | case SYS_DVBT2: | ||
63 | if (c->bandwidth_hz <= 6000000) { | ||
64 | /* IF 3570000 Hz, BW 6000000 Hz */ | ||
65 | memcpy(if_val, "\x2c\x94\xdb", 3); | ||
66 | memcpy(bw_val, "\xbf\x55\x55\x15\x6b\x15\x6b", 7); | ||
67 | bw_val2 = 0x02; | ||
68 | } else if (c->bandwidth_hz <= 7000000) { | ||
69 | /* IF 4570000 Hz, BW 7000000 Hz */ | ||
70 | memcpy(if_val, "\x39\x11\xbc", 3); | ||
71 | memcpy(bw_val, "\xa4\x00\x00\x0f\x2c\x0f\x2c", 7); | ||
72 | bw_val2 = 0x01; | ||
73 | } else if (c->bandwidth_hz <= 8000000) { | ||
74 | /* IF 4570000 Hz, BW 8000000 Hz */ | ||
75 | memcpy(if_val, "\x39\x11\xbc", 3); | ||
76 | memcpy(bw_val, "\x8f\x80\x00\x08\xee\x08\xee", 7); | ||
77 | bw_val2 = 0x00; | ||
78 | } else { | ||
79 | ret = -EINVAL; | ||
80 | goto err; | ||
81 | } | ||
82 | break; | ||
83 | case SYS_DVBC_ANNEX_A: | ||
84 | /* IF 5070000 Hz, BW 8000000 Hz */ | ||
85 | memcpy(if_val, "\x3f\x50\x2c", 3); | ||
86 | memcpy(bw_val, "\x8f\x80\x00\x08\xee\x08\xee", 7); | ||
87 | bw_val2 = 0x00; | ||
88 | break; | ||
89 | default: | ||
90 | ret = -EINVAL; | ||
91 | goto err; | ||
92 | } | ||
93 | |||
94 | /* program tuner */ | ||
95 | if (fe->ops.tuner_ops.set_params) { | ||
96 | ret = fe->ops.tuner_ops.set_params(fe); | ||
97 | if (ret) | ||
98 | goto err; | ||
99 | } | ||
100 | |||
101 | if (fe->ops.tuner_ops.get_if_frequency) { | ||
102 | ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency); | ||
103 | if (ret) | ||
104 | goto err; | ||
105 | |||
106 | dev_dbg(&client->dev, "get_if_frequency=%d\n", if_frequency); | ||
107 | } | ||
108 | |||
109 | switch (if_frequency) { | ||
110 | case 3570000: | ||
111 | case 4570000: | ||
112 | case 5070000: | ||
113 | break; | ||
114 | default: | ||
115 | dev_err(&client->dev, "IF frequency %d not supported\n", | ||
116 | if_frequency); | ||
117 | ret = -EINVAL; | ||
118 | goto err; | ||
119 | } | ||
120 | |||
121 | ret = regmap_write(dev->regmap[2], 0xfb, 0x13); | ||
122 | ret = regmap_write(dev->regmap[2], 0xef, 0x13); | ||
123 | ret = regmap_write(dev->regmap[2], 0xf9, 0x13); | ||
124 | if (ret) | ||
125 | goto err; | ||
126 | |||
127 | ret = regmap_write(dev->regmap[2], 0x00, 0x66); | ||
128 | if (ret) | ||
129 | goto err; | ||
130 | ret = regmap_write(dev->regmap[2], 0x01, 0x00); | ||
131 | if (ret) | ||
132 | goto err; | ||
133 | ret = regmap_write(dev->regmap[2], 0x02, 0x01); | ||
134 | if (ret) | ||
135 | goto err; | ||
136 | ret = regmap_write(dev->regmap[2], 0x03, delivery_system_val); | ||
137 | if (ret) | ||
138 | goto err; | ||
139 | ret = regmap_write(dev->regmap[2], 0x04, bw_val2); | ||
140 | if (ret) | ||
141 | goto err; | ||
142 | |||
143 | for (i = 0; i < sizeof(if_val); i++) { | ||
144 | ret = regmap_write(dev->regmap[2], 0x10 + i, if_val[i]); | ||
145 | if (ret) | ||
146 | goto err; | ||
147 | } | ||
148 | |||
149 | for (i = 0; i < sizeof(bw_val); i++) { | ||
150 | ret = regmap_write(dev->regmap[2], 0x13 + i, bw_val[i]); | ||
151 | if (ret) | ||
152 | goto err; | ||
153 | } | ||
154 | |||
155 | switch (c->delivery_system) { | ||
156 | case SYS_DVBT: | ||
157 | ret = regmap_write(dev->regmap[0], 0x07, 0x26); | ||
158 | ret = regmap_write(dev->regmap[0], 0xb0, 0x0a); | ||
159 | ret = regmap_write(dev->regmap[0], 0xb4, 0x00); | ||
160 | ret = regmap_write(dev->regmap[0], 0xcd, 0x1f); | ||
161 | ret = regmap_write(dev->regmap[0], 0xd4, 0x0a); | ||
162 | ret = regmap_write(dev->regmap[0], 0xd6, 0x48); | ||
163 | ret = regmap_write(dev->regmap[0], 0x00, 0xba); | ||
164 | ret = regmap_write(dev->regmap[0], 0x01, 0x13); | ||
165 | if (ret) | ||
166 | goto err; | ||
167 | break; | ||
168 | case SYS_DVBT2: | ||
169 | ret = regmap_write(dev->regmap[2], 0x2b, 0x13); | ||
170 | ret = regmap_write(dev->regmap[2], 0x4f, 0x05); | ||
171 | ret = regmap_write(dev->regmap[1], 0xf6, 0x05); | ||
172 | ret = regmap_write(dev->regmap[0], 0xb0, 0x0a); | ||
173 | ret = regmap_write(dev->regmap[0], 0xb4, 0xf6); | ||
174 | ret = regmap_write(dev->regmap[0], 0xcd, 0x01); | ||
175 | ret = regmap_write(dev->regmap[0], 0xd4, 0x09); | ||
176 | ret = regmap_write(dev->regmap[0], 0xd6, 0x46); | ||
177 | ret = regmap_write(dev->regmap[2], 0x30, 0x80); | ||
178 | ret = regmap_write(dev->regmap[2], 0x32, 0x00); | ||
179 | if (ret) | ||
180 | goto err; | ||
181 | break; | ||
182 | case SYS_DVBC_ANNEX_A: | ||
183 | ret = regmap_write(dev->regmap[0], 0xb0, 0x0b); | ||
184 | ret = regmap_write(dev->regmap[0], 0xb4, 0x00); | ||
185 | ret = regmap_write(dev->regmap[0], 0xcd, 0x17); | ||
186 | ret = regmap_write(dev->regmap[0], 0xd4, 0x09); | ||
187 | ret = regmap_write(dev->regmap[0], 0xd6, 0x48); | ||
188 | ret = regmap_write(dev->regmap[1], 0x00, 0xb0); | ||
189 | if (ret) | ||
190 | goto err; | ||
191 | break; | ||
192 | default: | ||
193 | ret = -EINVAL; | ||
194 | goto err; | ||
195 | } | ||
196 | |||
197 | ret = regmap_write(dev->regmap[0], 0x46, 0x00); | ||
198 | ret = regmap_write(dev->regmap[0], 0xae, 0x00); | ||
199 | ret = regmap_write(dev->regmap[2], 0x08, 0x1d); | ||
200 | ret = regmap_write(dev->regmap[0], 0xd9, 0xe3); | ||
201 | ret = regmap_write(dev->regmap[2], 0xf8, 0x9f); | ||
202 | if (ret) | ||
203 | goto err; | ||
204 | |||
205 | dev->delivery_system = c->delivery_system; | ||
206 | |||
207 | return 0; | ||
208 | err: | ||
209 | dev_dbg(&client->dev, "failed=%d\n", ret); | ||
210 | return ret; | ||
211 | } | ||
212 | |||
213 | static int mn88472_read_status(struct dvb_frontend *fe, fe_status_t *status) | ||
214 | { | ||
215 | struct i2c_client *client = fe->demodulator_priv; | ||
216 | struct mn88472_dev *dev = i2c_get_clientdata(client); | ||
217 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
218 | int ret; | ||
219 | unsigned int utmp; | ||
220 | |||
221 | *status = 0; | ||
222 | |||
223 | if (!dev->warm) { | ||
224 | ret = -EAGAIN; | ||
225 | goto err; | ||
226 | } | ||
227 | |||
228 | switch (c->delivery_system) { | ||
229 | case SYS_DVBT: | ||
230 | case SYS_DVBT2: | ||
231 | /* FIXME: implement me */ | ||
232 | utmp = 0x08; /* DVB-C lock value */ | ||
233 | break; | ||
234 | case SYS_DVBC_ANNEX_A: | ||
235 | ret = regmap_read(dev->regmap[1], 0x84, &utmp); | ||
236 | if (ret) | ||
237 | goto err; | ||
238 | break; | ||
239 | default: | ||
240 | ret = -EINVAL; | ||
241 | goto err; | ||
242 | } | ||
243 | |||
244 | if (utmp == 0x08) | ||
245 | *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | | ||
246 | FE_HAS_SYNC | FE_HAS_LOCK; | ||
247 | |||
248 | return 0; | ||
249 | err: | ||
250 | dev_dbg(&client->dev, "failed=%d\n", ret); | ||
251 | return ret; | ||
252 | } | ||
253 | |||
254 | static int mn88472_init(struct dvb_frontend *fe) | ||
255 | { | ||
256 | struct i2c_client *client = fe->demodulator_priv; | ||
257 | struct mn88472_dev *dev = i2c_get_clientdata(client); | ||
258 | int ret, len, remaining; | ||
259 | const struct firmware *fw = NULL; | ||
260 | u8 *fw_file = MN88472_FIRMWARE; | ||
261 | |||
262 | dev_dbg(&client->dev, "\n"); | ||
263 | |||
264 | /* set cold state by default */ | ||
265 | dev->warm = false; | ||
266 | |||
267 | /* power on */ | ||
268 | ret = regmap_write(dev->regmap[2], 0x05, 0x00); | ||
269 | if (ret) | ||
270 | goto err; | ||
271 | |||
272 | ret = regmap_bulk_write(dev->regmap[2], 0x0b, "\x00\x00", 2); | ||
273 | if (ret) | ||
274 | goto err; | ||
275 | |||
276 | /* request the firmware, this will block and timeout */ | ||
277 | ret = request_firmware(&fw, fw_file, &client->dev); | ||
278 | if (ret) { | ||
279 | dev_err(&client->dev, "firmare file '%s' not found\n", | ||
280 | fw_file); | ||
281 | goto err; | ||
282 | } | ||
283 | |||
284 | dev_info(&client->dev, "downloading firmware from file '%s'\n", | ||
285 | fw_file); | ||
286 | |||
287 | ret = regmap_write(dev->regmap[0], 0xf5, 0x03); | ||
288 | if (ret) | ||
289 | goto err; | ||
290 | |||
291 | for (remaining = fw->size; remaining > 0; | ||
292 | remaining -= (dev->i2c_wr_max - 1)) { | ||
293 | len = remaining; | ||
294 | if (len > (dev->i2c_wr_max - 1)) | ||
295 | len = (dev->i2c_wr_max - 1); | ||
296 | |||
297 | ret = regmap_bulk_write(dev->regmap[0], 0xf6, | ||
298 | &fw->data[fw->size - remaining], len); | ||
299 | if (ret) { | ||
300 | dev_err(&client->dev, | ||
301 | "firmware download failed=%d\n", ret); | ||
302 | goto err; | ||
303 | } | ||
304 | } | ||
305 | |||
306 | ret = regmap_write(dev->regmap[0], 0xf5, 0x00); | ||
307 | if (ret) | ||
308 | goto err; | ||
309 | |||
310 | release_firmware(fw); | ||
311 | fw = NULL; | ||
312 | |||
313 | /* warm state */ | ||
314 | dev->warm = true; | ||
315 | |||
316 | return 0; | ||
317 | err: | ||
318 | if (fw) | ||
319 | release_firmware(fw); | ||
320 | |||
321 | dev_dbg(&client->dev, "failed=%d\n", ret); | ||
322 | return ret; | ||
323 | } | ||
324 | |||
325 | static int mn88472_sleep(struct dvb_frontend *fe) | ||
326 | { | ||
327 | struct i2c_client *client = fe->demodulator_priv; | ||
328 | struct mn88472_dev *dev = i2c_get_clientdata(client); | ||
329 | int ret; | ||
330 | |||
331 | dev_dbg(&client->dev, "\n"); | ||
332 | |||
333 | /* power off */ | ||
334 | ret = regmap_write(dev->regmap[2], 0x0b, 0x30); | ||
335 | |||
336 | if (ret) | ||
337 | goto err; | ||
338 | |||
339 | ret = regmap_write(dev->regmap[2], 0x05, 0x3e); | ||
340 | if (ret) | ||
341 | goto err; | ||
342 | |||
343 | dev->delivery_system = SYS_UNDEFINED; | ||
344 | |||
345 | return 0; | ||
346 | err: | ||
347 | dev_dbg(&client->dev, "failed=%d\n", ret); | ||
348 | return ret; | ||
349 | } | ||
350 | |||
351 | static struct dvb_frontend_ops mn88472_ops = { | ||
352 | .delsys = {SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A}, | ||
353 | .info = { | ||
354 | .name = "Panasonic MN88472", | ||
355 | .caps = FE_CAN_FEC_1_2 | | ||
356 | FE_CAN_FEC_2_3 | | ||
357 | FE_CAN_FEC_3_4 | | ||
358 | FE_CAN_FEC_5_6 | | ||
359 | FE_CAN_FEC_7_8 | | ||
360 | FE_CAN_FEC_AUTO | | ||
361 | FE_CAN_QPSK | | ||
362 | FE_CAN_QAM_16 | | ||
363 | FE_CAN_QAM_32 | | ||
364 | FE_CAN_QAM_64 | | ||
365 | FE_CAN_QAM_128 | | ||
366 | FE_CAN_QAM_256 | | ||
367 | FE_CAN_QAM_AUTO | | ||
368 | FE_CAN_TRANSMISSION_MODE_AUTO | | ||
369 | FE_CAN_GUARD_INTERVAL_AUTO | | ||
370 | FE_CAN_HIERARCHY_AUTO | | ||
371 | FE_CAN_MUTE_TS | | ||
372 | FE_CAN_2G_MODULATION | | ||
373 | FE_CAN_MULTISTREAM | ||
374 | }, | ||
375 | |||
376 | .get_tune_settings = mn88472_get_tune_settings, | ||
377 | |||
378 | .init = mn88472_init, | ||
379 | .sleep = mn88472_sleep, | ||
380 | |||
381 | .set_frontend = mn88472_set_frontend, | ||
382 | |||
383 | .read_status = mn88472_read_status, | ||
384 | }; | ||
385 | |||
386 | static int mn88472_probe(struct i2c_client *client, | ||
387 | const struct i2c_device_id *id) | ||
388 | { | ||
389 | struct mn88472_config *config = client->dev.platform_data; | ||
390 | struct mn88472_dev *dev; | ||
391 | int ret; | ||
392 | unsigned int utmp; | ||
393 | static const struct regmap_config regmap_config = { | ||
394 | .reg_bits = 8, | ||
395 | .val_bits = 8, | ||
396 | }; | ||
397 | |||
398 | dev_dbg(&client->dev, "\n"); | ||
399 | |||
400 | /* Caller really need to provide pointer for frontend we create. */ | ||
401 | if (config->fe == NULL) { | ||
402 | dev_err(&client->dev, "frontend pointer not defined\n"); | ||
403 | ret = -EINVAL; | ||
404 | goto err; | ||
405 | } | ||
406 | |||
407 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | ||
408 | if (dev == NULL) { | ||
409 | ret = -ENOMEM; | ||
410 | goto err; | ||
411 | } | ||
412 | |||
413 | dev->i2c_wr_max = config->i2c_wr_max; | ||
414 | dev->client[0] = client; | ||
415 | dev->regmap[0] = regmap_init_i2c(dev->client[0], ®map_config); | ||
416 | if (IS_ERR(dev->regmap[0])) { | ||
417 | ret = PTR_ERR(dev->regmap[0]); | ||
418 | goto err_kfree; | ||
419 | } | ||
420 | |||
421 | /* check demod answers to I2C */ | ||
422 | ret = regmap_read(dev->regmap[0], 0x00, &utmp); | ||
423 | if (ret) | ||
424 | goto err_regmap_0_regmap_exit; | ||
425 | |||
426 | /* | ||
427 | * Chip has three I2C addresses for different register pages. Used | ||
428 | * addresses are 0x18, 0x1a and 0x1c. We register two dummy clients, | ||
429 | * 0x1a and 0x1c, in order to get own I2C client for each register page. | ||
430 | */ | ||
431 | dev->client[1] = i2c_new_dummy(client->adapter, 0x1a); | ||
432 | if (dev->client[1] == NULL) { | ||
433 | ret = -ENODEV; | ||
434 | dev_err(&client->dev, "I2C registration failed\n"); | ||
435 | if (ret) | ||
436 | goto err_regmap_0_regmap_exit; | ||
437 | } | ||
438 | dev->regmap[1] = regmap_init_i2c(dev->client[1], ®map_config); | ||
439 | if (IS_ERR(dev->regmap[1])) { | ||
440 | ret = PTR_ERR(dev->regmap[1]); | ||
441 | goto err_client_1_i2c_unregister_device; | ||
442 | } | ||
443 | i2c_set_clientdata(dev->client[1], dev); | ||
444 | |||
445 | dev->client[2] = i2c_new_dummy(client->adapter, 0x1c); | ||
446 | if (dev->client[2] == NULL) { | ||
447 | ret = -ENODEV; | ||
448 | dev_err(&client->dev, "2nd I2C registration failed\n"); | ||
449 | if (ret) | ||
450 | goto err_regmap_1_regmap_exit; | ||
451 | } | ||
452 | dev->regmap[2] = regmap_init_i2c(dev->client[2], ®map_config); | ||
453 | if (IS_ERR(dev->regmap[2])) { | ||
454 | ret = PTR_ERR(dev->regmap[2]); | ||
455 | goto err_client_2_i2c_unregister_device; | ||
456 | } | ||
457 | i2c_set_clientdata(dev->client[2], dev); | ||
458 | |||
459 | /* create dvb_frontend */ | ||
460 | memcpy(&dev->fe.ops, &mn88472_ops, sizeof(struct dvb_frontend_ops)); | ||
461 | dev->fe.demodulator_priv = client; | ||
462 | *config->fe = &dev->fe; | ||
463 | i2c_set_clientdata(client, dev); | ||
464 | |||
465 | dev_info(&client->dev, "Panasonic MN88472 successfully attached\n"); | ||
466 | return 0; | ||
467 | |||
468 | err_client_2_i2c_unregister_device: | ||
469 | i2c_unregister_device(dev->client[2]); | ||
470 | err_regmap_1_regmap_exit: | ||
471 | regmap_exit(dev->regmap[1]); | ||
472 | err_client_1_i2c_unregister_device: | ||
473 | i2c_unregister_device(dev->client[1]); | ||
474 | err_regmap_0_regmap_exit: | ||
475 | regmap_exit(dev->regmap[0]); | ||
476 | err_kfree: | ||
477 | kfree(dev); | ||
478 | err: | ||
479 | dev_dbg(&client->dev, "failed=%d\n", ret); | ||
480 | return ret; | ||
481 | } | ||
482 | |||
483 | static int mn88472_remove(struct i2c_client *client) | ||
484 | { | ||
485 | struct mn88472_dev *dev = i2c_get_clientdata(client); | ||
486 | |||
487 | dev_dbg(&client->dev, "\n"); | ||
488 | |||
489 | regmap_exit(dev->regmap[2]); | ||
490 | i2c_unregister_device(dev->client[2]); | ||
491 | |||
492 | regmap_exit(dev->regmap[1]); | ||
493 | i2c_unregister_device(dev->client[1]); | ||
494 | |||
495 | regmap_exit(dev->regmap[0]); | ||
496 | |||
497 | kfree(dev); | ||
498 | |||
499 | return 0; | ||
500 | } | ||
501 | |||
502 | static const struct i2c_device_id mn88472_id_table[] = { | ||
503 | {"mn88472", 0}, | ||
504 | {} | ||
505 | }; | ||
506 | MODULE_DEVICE_TABLE(i2c, mn88472_id_table); | ||
507 | |||
508 | static struct i2c_driver mn88472_driver = { | ||
509 | .driver = { | ||
510 | .owner = THIS_MODULE, | ||
511 | .name = "mn88472", | ||
512 | }, | ||
513 | .probe = mn88472_probe, | ||
514 | .remove = mn88472_remove, | ||
515 | .id_table = mn88472_id_table, | ||
516 | }; | ||
517 | |||
518 | module_i2c_driver(mn88472_driver); | ||
519 | |||
520 | MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); | ||
521 | MODULE_DESCRIPTION("Panasonic MN88472 DVB-T/T2/C demodulator driver"); | ||
522 | MODULE_LICENSE("GPL"); | ||
523 | MODULE_FIRMWARE(MN88472_FIRMWARE); | ||
diff --git a/drivers/staging/media/mn88472/mn88472_priv.h b/drivers/staging/media/mn88472/mn88472_priv.h new file mode 100644 index 000000000000..1095949f040d --- /dev/null +++ b/drivers/staging/media/mn88472/mn88472_priv.h | |||
@@ -0,0 +1,36 @@ | |||
1 | /* | ||
2 | * Panasonic MN88472 DVB-T/T2/C demodulator driver | ||
3 | * | ||
4 | * Copyright (C) 2013 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 | #ifndef MN88472_PRIV_H | ||
18 | #define MN88472_PRIV_H | ||
19 | |||
20 | #include "dvb_frontend.h" | ||
21 | #include "mn88472.h" | ||
22 | #include <linux/firmware.h> | ||
23 | #include <linux/regmap.h> | ||
24 | |||
25 | #define MN88472_FIRMWARE "dvb-demod-mn88472-02.fw" | ||
26 | |||
27 | struct mn88472_dev { | ||
28 | struct i2c_client *client[3]; | ||
29 | struct regmap *regmap[3]; | ||
30 | struct dvb_frontend fe; | ||
31 | u16 i2c_wr_max; | ||
32 | fe_delivery_system_t delivery_system; | ||
33 | bool warm; /* FW running */ | ||
34 | }; | ||
35 | |||
36 | #endif | ||