1 // SPDX-License-Identifier: GPL-2.0
3 * c8sectpfe-common.c - C8SECTPFE STi DVB driver
5 * Copyright (c) STMicroelectronics 2015
7 * Author: Peter Griffin <peter.griffin@linaro.org>
10 #include <linux/completion.h>
11 #include <linux/delay.h>
12 #include <linux/device.h>
13 #include <linux/dvb/dmx.h>
14 #include <linux/errno.h>
15 #include <linux/init.h>
16 #include <linux/interrupt.h>
18 #include <linux/ioport.h>
19 #include <linux/module.h>
20 #include <linux/slab.h>
21 #include <linux/time.h>
22 #include <linux/wait.h>
24 #include <media/dmxdev.h>
25 #include <media/dvbdev.h>
26 #include <media/dvb_demux.h>
27 #include <media/dvb_frontend.h>
28 #include <media/dvb_net.h>
30 #include "c8sectpfe-common.h"
31 #include "c8sectpfe-core.h"
32 #include "c8sectpfe-dvb.h"
34 static int register_dvb(struct stdemux
*demux
, struct dvb_adapter
*adap
,
35 void *start_feed
, void *stop_feed
,
36 struct c8sectpfei
*fei
)
40 demux
->dvb_demux
.dmx
.capabilities
= DMX_TS_FILTERING
|
41 DMX_SECTION_FILTERING
|
42 DMX_MEMORY_BASED_FILTERING
;
44 demux
->dvb_demux
.priv
= demux
;
45 demux
->dvb_demux
.filternum
= C8SECTPFE_MAXCHANNEL
;
46 demux
->dvb_demux
.feednum
= C8SECTPFE_MAXCHANNEL
;
48 demux
->dvb_demux
.start_feed
= start_feed
;
49 demux
->dvb_demux
.stop_feed
= stop_feed
;
50 demux
->dvb_demux
.write_to_decoder
= NULL
;
52 result
= dvb_dmx_init(&demux
->dvb_demux
);
54 dev_err(fei
->dev
, "dvb_dmx_init failed (errno = %d)\n",
59 demux
->dmxdev
.filternum
= demux
->dvb_demux
.filternum
;
60 demux
->dmxdev
.demux
= &demux
->dvb_demux
.dmx
;
61 demux
->dmxdev
.capabilities
= 0;
63 result
= dvb_dmxdev_init(&demux
->dmxdev
, adap
);
65 dev_err(fei
->dev
, "dvb_dmxdev_init failed (errno = %d)\n",
71 demux
->hw_frontend
.source
= DMX_FRONTEND_0
+ demux
->tsin_index
;
73 result
= demux
->dvb_demux
.dmx
.add_frontend(&demux
->dvb_demux
.dmx
,
76 dev_err(fei
->dev
, "add_frontend failed (errno = %d)\n", result
);
80 demux
->mem_frontend
.source
= DMX_MEMORY_FE
;
81 result
= demux
->dvb_demux
.dmx
.add_frontend(&demux
->dvb_demux
.dmx
,
82 &demux
->mem_frontend
);
84 dev_err(fei
->dev
, "add_frontend failed (%d)\n", result
);
88 result
= demux
->dvb_demux
.dmx
.connect_frontend(&demux
->dvb_demux
.dmx
,
91 dev_err(fei
->dev
, "connect_frontend (%d)\n", result
);
98 demux
->dvb_demux
.dmx
.remove_frontend(&demux
->dvb_demux
.dmx
,
99 &demux
->mem_frontend
);
101 demux
->dvb_demux
.dmx
.remove_frontend(&demux
->dvb_demux
.dmx
,
102 &demux
->hw_frontend
);
104 dvb_dmxdev_release(&demux
->dmxdev
);
106 dvb_dmx_release(&demux
->dvb_demux
);
112 static void unregister_dvb(struct stdemux
*demux
)
115 demux
->dvb_demux
.dmx
.remove_frontend(&demux
->dvb_demux
.dmx
,
116 &demux
->mem_frontend
);
118 demux
->dvb_demux
.dmx
.remove_frontend(&demux
->dvb_demux
.dmx
,
119 &demux
->hw_frontend
);
121 dvb_dmxdev_release(&demux
->dmxdev
);
123 dvb_dmx_release(&demux
->dvb_demux
);
126 static struct c8sectpfe
*c8sectpfe_create(struct c8sectpfei
*fei
,
130 struct c8sectpfe
*c8sectpfe
;
134 short int ids
[] = { -1 };
136 c8sectpfe
= kzalloc(sizeof(struct c8sectpfe
), GFP_KERNEL
);
140 mutex_init(&c8sectpfe
->lock
);
142 c8sectpfe
->device
= fei
->dev
;
144 result
= dvb_register_adapter(&c8sectpfe
->adapter
, "STi c8sectpfe",
145 THIS_MODULE
, fei
->dev
, ids
);
147 dev_err(fei
->dev
, "dvb_register_adapter failed (errno = %d)\n",
152 c8sectpfe
->adapter
.priv
= fei
;
154 for (i
= 0; i
< fei
->tsin_count
; i
++) {
156 c8sectpfe
->demux
[i
].tsin_index
= i
;
157 c8sectpfe
->demux
[i
].c8sectpfei
= fei
;
159 result
= register_dvb(&c8sectpfe
->demux
[i
], &c8sectpfe
->adapter
,
160 start_feed
, stop_feed
, fei
);
163 "register_dvb feed=%d failed (errno = %d)\n",
166 /* we take a all or nothing approach */
167 for (j
= 0; j
< i
; j
++)
168 unregister_dvb(&c8sectpfe
->demux
[j
]);
173 c8sectpfe
->num_feeds
= fei
->tsin_count
;
177 dvb_unregister_adapter(&c8sectpfe
->adapter
);
184 static void c8sectpfe_delete(struct c8sectpfe
*c8sectpfe
)
191 for (i
= 0; i
< c8sectpfe
->num_feeds
; i
++)
192 unregister_dvb(&c8sectpfe
->demux
[i
]);
194 dvb_unregister_adapter(&c8sectpfe
->adapter
);
199 void c8sectpfe_tuner_unregister_frontend(struct c8sectpfe
*c8sectpfe
,
200 struct c8sectpfei
*fei
)
203 struct channel_info
*tsin
;
205 for (n
= 0; n
< fei
->tsin_count
; n
++) {
207 tsin
= fei
->channel_data
[n
];
210 if (tsin
->frontend
) {
211 dvb_unregister_frontend(tsin
->frontend
);
212 dvb_frontend_detach(tsin
->frontend
);
215 i2c_put_adapter(tsin
->i2c_adapter
);
217 if (tsin
->i2c_client
) {
218 module_put(tsin
->i2c_client
->dev
.driver
->owner
);
219 i2c_unregister_device(tsin
->i2c_client
);
224 c8sectpfe_delete(c8sectpfe
);
227 int c8sectpfe_tuner_register_frontend(struct c8sectpfe
**c8sectpfe
,
228 struct c8sectpfei
*fei
,
232 struct channel_info
*tsin
;
233 struct dvb_frontend
*frontend
;
236 *c8sectpfe
= c8sectpfe_create(fei
, start_feed
, stop_feed
);
240 for (n
= 0; n
< fei
->tsin_count
; n
++) {
241 tsin
= fei
->channel_data
[n
];
243 res
= c8sectpfe_frontend_attach(&frontend
, *c8sectpfe
, tsin
, n
);
247 res
= dvb_register_frontend(&c8sectpfe
[0]->adapter
, frontend
);
249 dev_err(fei
->dev
, "dvb_register_frontend failed (%d)\n",
254 tsin
->frontend
= frontend
;
260 c8sectpfe_tuner_unregister_frontend(*c8sectpfe
, fei
);