Merge tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost
[cris-mirror.git] / drivers / media / platform / sti / c8sectpfe / c8sectpfe-common.c
blob5df67da25525cbfec8b5890fdd626f634408a6f0
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * c8sectpfe-common.c - C8SECTPFE STi DVB driver
5 * Copyright (c) STMicroelectronics 2015
7 * Author: Peter Griffin <peter.griffin@linaro.org>
9 */
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>
17 #include <linux/io.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)
38 int result;
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);
53 if (result < 0) {
54 dev_err(fei->dev, "dvb_dmx_init failed (errno = %d)\n",
55 result);
56 goto err_dmx;
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);
64 if (result < 0) {
65 dev_err(fei->dev, "dvb_dmxdev_init failed (errno = %d)\n",
66 result);
68 goto err_dmxdev;
71 demux->hw_frontend.source = DMX_FRONTEND_0 + demux->tsin_index;
73 result = demux->dvb_demux.dmx.add_frontend(&demux->dvb_demux.dmx,
74 &demux->hw_frontend);
75 if (result < 0) {
76 dev_err(fei->dev, "add_frontend failed (errno = %d)\n", result);
77 goto err_fe_hw;
80 demux->mem_frontend.source = DMX_MEMORY_FE;
81 result = demux->dvb_demux.dmx.add_frontend(&demux->dvb_demux.dmx,
82 &demux->mem_frontend);
83 if (result < 0) {
84 dev_err(fei->dev, "add_frontend failed (%d)\n", result);
85 goto err_fe_mem;
88 result = demux->dvb_demux.dmx.connect_frontend(&demux->dvb_demux.dmx,
89 &demux->hw_frontend);
90 if (result < 0) {
91 dev_err(fei->dev, "connect_frontend (%d)\n", result);
92 goto err_fe_con;
95 return 0;
97 err_fe_con:
98 demux->dvb_demux.dmx.remove_frontend(&demux->dvb_demux.dmx,
99 &demux->mem_frontend);
100 err_fe_mem:
101 demux->dvb_demux.dmx.remove_frontend(&demux->dvb_demux.dmx,
102 &demux->hw_frontend);
103 err_fe_hw:
104 dvb_dmxdev_release(&demux->dmxdev);
105 err_dmxdev:
106 dvb_dmx_release(&demux->dvb_demux);
107 err_dmx:
108 return result;
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,
127 void *start_feed,
128 void *stop_feed)
130 struct c8sectpfe *c8sectpfe;
131 int result;
132 int i, j;
134 short int ids[] = { -1 };
136 c8sectpfe = kzalloc(sizeof(struct c8sectpfe), GFP_KERNEL);
137 if (!c8sectpfe)
138 goto err1;
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);
146 if (result < 0) {
147 dev_err(fei->dev, "dvb_register_adapter failed (errno = %d)\n",
148 result);
149 goto err2;
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);
161 if (result < 0) {
162 dev_err(fei->dev,
163 "register_dvb feed=%d failed (errno = %d)\n",
164 result, i);
166 /* we take a all or nothing approach */
167 for (j = 0; j < i; j++)
168 unregister_dvb(&c8sectpfe->demux[j]);
169 goto err3;
173 c8sectpfe->num_feeds = fei->tsin_count;
175 return c8sectpfe;
176 err3:
177 dvb_unregister_adapter(&c8sectpfe->adapter);
178 err2:
179 kfree(c8sectpfe);
180 err1:
181 return NULL;
184 static void c8sectpfe_delete(struct c8sectpfe *c8sectpfe)
186 int i;
188 if (!c8sectpfe)
189 return;
191 for (i = 0; i < c8sectpfe->num_feeds; i++)
192 unregister_dvb(&c8sectpfe->demux[i]);
194 dvb_unregister_adapter(&c8sectpfe->adapter);
196 kfree(c8sectpfe);
199 void c8sectpfe_tuner_unregister_frontend(struct c8sectpfe *c8sectpfe,
200 struct c8sectpfei *fei)
202 int n;
203 struct channel_info *tsin;
205 for (n = 0; n < fei->tsin_count; n++) {
207 tsin = fei->channel_data[n];
209 if (tsin) {
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,
229 void *start_feed,
230 void *stop_feed)
232 struct channel_info *tsin;
233 struct dvb_frontend *frontend;
234 int n, res;
236 *c8sectpfe = c8sectpfe_create(fei, start_feed, stop_feed);
237 if (!*c8sectpfe)
238 return -ENOMEM;
240 for (n = 0; n < fei->tsin_count; n++) {
241 tsin = fei->channel_data[n];
243 res = c8sectpfe_frontend_attach(&frontend, *c8sectpfe, tsin, n);
244 if (res)
245 goto err;
247 res = dvb_register_frontend(&c8sectpfe[0]->adapter, frontend);
248 if (res < 0) {
249 dev_err(fei->dev, "dvb_register_frontend failed (%d)\n",
250 res);
251 goto err;
254 tsin->frontend = frontend;
257 return 0;
259 err:
260 c8sectpfe_tuner_unregister_frontend(*c8sectpfe, fei);
261 return res;