xref: /openbmc/linux/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-common.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1*e7b8153eSMauro Carvalho Chehab // SPDX-License-Identifier: GPL-2.0
2*e7b8153eSMauro Carvalho Chehab /*
3*e7b8153eSMauro Carvalho Chehab  * c8sectpfe-common.c - C8SECTPFE STi DVB driver
4*e7b8153eSMauro Carvalho Chehab  *
5*e7b8153eSMauro Carvalho Chehab  * Copyright (c) STMicroelectronics 2015
6*e7b8153eSMauro Carvalho Chehab  *
7*e7b8153eSMauro Carvalho Chehab  *   Author: Peter Griffin <peter.griffin@linaro.org>
8*e7b8153eSMauro Carvalho Chehab  *
9*e7b8153eSMauro Carvalho Chehab  */
10*e7b8153eSMauro Carvalho Chehab #include <linux/completion.h>
11*e7b8153eSMauro Carvalho Chehab #include <linux/delay.h>
12*e7b8153eSMauro Carvalho Chehab #include <linux/device.h>
13*e7b8153eSMauro Carvalho Chehab #include <linux/dvb/dmx.h>
14*e7b8153eSMauro Carvalho Chehab #include <linux/errno.h>
15*e7b8153eSMauro Carvalho Chehab #include <linux/init.h>
16*e7b8153eSMauro Carvalho Chehab #include <linux/interrupt.h>
17*e7b8153eSMauro Carvalho Chehab #include <linux/io.h>
18*e7b8153eSMauro Carvalho Chehab #include <linux/ioport.h>
19*e7b8153eSMauro Carvalho Chehab #include <linux/module.h>
20*e7b8153eSMauro Carvalho Chehab #include <linux/slab.h>
21*e7b8153eSMauro Carvalho Chehab #include <linux/time.h>
22*e7b8153eSMauro Carvalho Chehab #include <linux/wait.h>
23*e7b8153eSMauro Carvalho Chehab 
24*e7b8153eSMauro Carvalho Chehab #include <media/dmxdev.h>
25*e7b8153eSMauro Carvalho Chehab #include <media/dvbdev.h>
26*e7b8153eSMauro Carvalho Chehab #include <media/dvb_demux.h>
27*e7b8153eSMauro Carvalho Chehab #include <media/dvb_frontend.h>
28*e7b8153eSMauro Carvalho Chehab #include <media/dvb_net.h>
29*e7b8153eSMauro Carvalho Chehab 
30*e7b8153eSMauro Carvalho Chehab #include "c8sectpfe-common.h"
31*e7b8153eSMauro Carvalho Chehab #include "c8sectpfe-core.h"
32*e7b8153eSMauro Carvalho Chehab #include "c8sectpfe-dvb.h"
33*e7b8153eSMauro Carvalho Chehab 
register_dvb(struct stdemux * demux,struct dvb_adapter * adap,void * start_feed,void * stop_feed,struct c8sectpfei * fei)34*e7b8153eSMauro Carvalho Chehab static int register_dvb(struct stdemux *demux, struct dvb_adapter *adap,
35*e7b8153eSMauro Carvalho Chehab 				void *start_feed, void *stop_feed,
36*e7b8153eSMauro Carvalho Chehab 				struct c8sectpfei *fei)
37*e7b8153eSMauro Carvalho Chehab {
38*e7b8153eSMauro Carvalho Chehab 	int result;
39*e7b8153eSMauro Carvalho Chehab 
40*e7b8153eSMauro Carvalho Chehab 	demux->dvb_demux.dmx.capabilities = DMX_TS_FILTERING |
41*e7b8153eSMauro Carvalho Chehab 					DMX_SECTION_FILTERING |
42*e7b8153eSMauro Carvalho Chehab 					DMX_MEMORY_BASED_FILTERING;
43*e7b8153eSMauro Carvalho Chehab 
44*e7b8153eSMauro Carvalho Chehab 	demux->dvb_demux.priv = demux;
45*e7b8153eSMauro Carvalho Chehab 	demux->dvb_demux.filternum = C8SECTPFE_MAXCHANNEL;
46*e7b8153eSMauro Carvalho Chehab 	demux->dvb_demux.feednum = C8SECTPFE_MAXCHANNEL;
47*e7b8153eSMauro Carvalho Chehab 
48*e7b8153eSMauro Carvalho Chehab 	demux->dvb_demux.start_feed = start_feed;
49*e7b8153eSMauro Carvalho Chehab 	demux->dvb_demux.stop_feed = stop_feed;
50*e7b8153eSMauro Carvalho Chehab 	demux->dvb_demux.write_to_decoder = NULL;
51*e7b8153eSMauro Carvalho Chehab 
52*e7b8153eSMauro Carvalho Chehab 	result = dvb_dmx_init(&demux->dvb_demux);
53*e7b8153eSMauro Carvalho Chehab 	if (result < 0) {
54*e7b8153eSMauro Carvalho Chehab 		dev_err(fei->dev, "dvb_dmx_init failed (errno = %d)\n",
55*e7b8153eSMauro Carvalho Chehab 			result);
56*e7b8153eSMauro Carvalho Chehab 		goto err_dmx;
57*e7b8153eSMauro Carvalho Chehab 	}
58*e7b8153eSMauro Carvalho Chehab 
59*e7b8153eSMauro Carvalho Chehab 	demux->dmxdev.filternum = demux->dvb_demux.filternum;
60*e7b8153eSMauro Carvalho Chehab 	demux->dmxdev.demux = &demux->dvb_demux.dmx;
61*e7b8153eSMauro Carvalho Chehab 	demux->dmxdev.capabilities = 0;
62*e7b8153eSMauro Carvalho Chehab 
63*e7b8153eSMauro Carvalho Chehab 	result = dvb_dmxdev_init(&demux->dmxdev, adap);
64*e7b8153eSMauro Carvalho Chehab 	if (result < 0) {
65*e7b8153eSMauro Carvalho Chehab 		dev_err(fei->dev, "dvb_dmxdev_init failed (errno = %d)\n",
66*e7b8153eSMauro Carvalho Chehab 			result);
67*e7b8153eSMauro Carvalho Chehab 
68*e7b8153eSMauro Carvalho Chehab 		goto err_dmxdev;
69*e7b8153eSMauro Carvalho Chehab 	}
70*e7b8153eSMauro Carvalho Chehab 
71*e7b8153eSMauro Carvalho Chehab 	demux->hw_frontend.source = DMX_FRONTEND_0 + demux->tsin_index;
72*e7b8153eSMauro Carvalho Chehab 
73*e7b8153eSMauro Carvalho Chehab 	result = demux->dvb_demux.dmx.add_frontend(&demux->dvb_demux.dmx,
74*e7b8153eSMauro Carvalho Chehab 						&demux->hw_frontend);
75*e7b8153eSMauro Carvalho Chehab 	if (result < 0) {
76*e7b8153eSMauro Carvalho Chehab 		dev_err(fei->dev, "add_frontend failed (errno = %d)\n", result);
77*e7b8153eSMauro Carvalho Chehab 		goto err_fe_hw;
78*e7b8153eSMauro Carvalho Chehab 	}
79*e7b8153eSMauro Carvalho Chehab 
80*e7b8153eSMauro Carvalho Chehab 	demux->mem_frontend.source = DMX_MEMORY_FE;
81*e7b8153eSMauro Carvalho Chehab 	result = demux->dvb_demux.dmx.add_frontend(&demux->dvb_demux.dmx,
82*e7b8153eSMauro Carvalho Chehab 						&demux->mem_frontend);
83*e7b8153eSMauro Carvalho Chehab 	if (result < 0) {
84*e7b8153eSMauro Carvalho Chehab 		dev_err(fei->dev, "add_frontend failed (%d)\n", result);
85*e7b8153eSMauro Carvalho Chehab 		goto err_fe_mem;
86*e7b8153eSMauro Carvalho Chehab 	}
87*e7b8153eSMauro Carvalho Chehab 
88*e7b8153eSMauro Carvalho Chehab 	result = demux->dvb_demux.dmx.connect_frontend(&demux->dvb_demux.dmx,
89*e7b8153eSMauro Carvalho Chehab 							&demux->hw_frontend);
90*e7b8153eSMauro Carvalho Chehab 	if (result < 0) {
91*e7b8153eSMauro Carvalho Chehab 		dev_err(fei->dev, "connect_frontend (%d)\n", result);
92*e7b8153eSMauro Carvalho Chehab 		goto err_fe_con;
93*e7b8153eSMauro Carvalho Chehab 	}
94*e7b8153eSMauro Carvalho Chehab 
95*e7b8153eSMauro Carvalho Chehab 	return 0;
96*e7b8153eSMauro Carvalho Chehab 
97*e7b8153eSMauro Carvalho Chehab err_fe_con:
98*e7b8153eSMauro Carvalho Chehab 	demux->dvb_demux.dmx.remove_frontend(&demux->dvb_demux.dmx,
99*e7b8153eSMauro Carvalho Chehab 						     &demux->mem_frontend);
100*e7b8153eSMauro Carvalho Chehab err_fe_mem:
101*e7b8153eSMauro Carvalho Chehab 	demux->dvb_demux.dmx.remove_frontend(&demux->dvb_demux.dmx,
102*e7b8153eSMauro Carvalho Chehab 						     &demux->hw_frontend);
103*e7b8153eSMauro Carvalho Chehab err_fe_hw:
104*e7b8153eSMauro Carvalho Chehab 	dvb_dmxdev_release(&demux->dmxdev);
105*e7b8153eSMauro Carvalho Chehab err_dmxdev:
106*e7b8153eSMauro Carvalho Chehab 	dvb_dmx_release(&demux->dvb_demux);
107*e7b8153eSMauro Carvalho Chehab err_dmx:
108*e7b8153eSMauro Carvalho Chehab 	return result;
109*e7b8153eSMauro Carvalho Chehab 
110*e7b8153eSMauro Carvalho Chehab }
111*e7b8153eSMauro Carvalho Chehab 
unregister_dvb(struct stdemux * demux)112*e7b8153eSMauro Carvalho Chehab static void unregister_dvb(struct stdemux *demux)
113*e7b8153eSMauro Carvalho Chehab {
114*e7b8153eSMauro Carvalho Chehab 
115*e7b8153eSMauro Carvalho Chehab 	demux->dvb_demux.dmx.remove_frontend(&demux->dvb_demux.dmx,
116*e7b8153eSMauro Carvalho Chehab 						     &demux->mem_frontend);
117*e7b8153eSMauro Carvalho Chehab 
118*e7b8153eSMauro Carvalho Chehab 	demux->dvb_demux.dmx.remove_frontend(&demux->dvb_demux.dmx,
119*e7b8153eSMauro Carvalho Chehab 						     &demux->hw_frontend);
120*e7b8153eSMauro Carvalho Chehab 
121*e7b8153eSMauro Carvalho Chehab 	dvb_dmxdev_release(&demux->dmxdev);
122*e7b8153eSMauro Carvalho Chehab 
123*e7b8153eSMauro Carvalho Chehab 	dvb_dmx_release(&demux->dvb_demux);
124*e7b8153eSMauro Carvalho Chehab }
125*e7b8153eSMauro Carvalho Chehab 
c8sectpfe_create(struct c8sectpfei * fei,void * start_feed,void * stop_feed)126*e7b8153eSMauro Carvalho Chehab static struct c8sectpfe *c8sectpfe_create(struct c8sectpfei *fei,
127*e7b8153eSMauro Carvalho Chehab 				void *start_feed,
128*e7b8153eSMauro Carvalho Chehab 				void *stop_feed)
129*e7b8153eSMauro Carvalho Chehab {
130*e7b8153eSMauro Carvalho Chehab 	struct c8sectpfe *c8sectpfe;
131*e7b8153eSMauro Carvalho Chehab 	int result;
132*e7b8153eSMauro Carvalho Chehab 	int i, j;
133*e7b8153eSMauro Carvalho Chehab 
134*e7b8153eSMauro Carvalho Chehab 	short int ids[] = { -1 };
135*e7b8153eSMauro Carvalho Chehab 
136*e7b8153eSMauro Carvalho Chehab 	c8sectpfe = kzalloc(sizeof(struct c8sectpfe), GFP_KERNEL);
137*e7b8153eSMauro Carvalho Chehab 	if (!c8sectpfe)
138*e7b8153eSMauro Carvalho Chehab 		goto err1;
139*e7b8153eSMauro Carvalho Chehab 
140*e7b8153eSMauro Carvalho Chehab 	mutex_init(&c8sectpfe->lock);
141*e7b8153eSMauro Carvalho Chehab 
142*e7b8153eSMauro Carvalho Chehab 	c8sectpfe->device = fei->dev;
143*e7b8153eSMauro Carvalho Chehab 
144*e7b8153eSMauro Carvalho Chehab 	result = dvb_register_adapter(&c8sectpfe->adapter, "STi c8sectpfe",
145*e7b8153eSMauro Carvalho Chehab 					THIS_MODULE, fei->dev, ids);
146*e7b8153eSMauro Carvalho Chehab 	if (result < 0) {
147*e7b8153eSMauro Carvalho Chehab 		dev_err(fei->dev, "dvb_register_adapter failed (errno = %d)\n",
148*e7b8153eSMauro Carvalho Chehab 			result);
149*e7b8153eSMauro Carvalho Chehab 		goto err2;
150*e7b8153eSMauro Carvalho Chehab 	}
151*e7b8153eSMauro Carvalho Chehab 
152*e7b8153eSMauro Carvalho Chehab 	c8sectpfe->adapter.priv = fei;
153*e7b8153eSMauro Carvalho Chehab 
154*e7b8153eSMauro Carvalho Chehab 	for (i = 0; i < fei->tsin_count; i++) {
155*e7b8153eSMauro Carvalho Chehab 
156*e7b8153eSMauro Carvalho Chehab 		c8sectpfe->demux[i].tsin_index = i;
157*e7b8153eSMauro Carvalho Chehab 		c8sectpfe->demux[i].c8sectpfei = fei;
158*e7b8153eSMauro Carvalho Chehab 
159*e7b8153eSMauro Carvalho Chehab 		result = register_dvb(&c8sectpfe->demux[i], &c8sectpfe->adapter,
160*e7b8153eSMauro Carvalho Chehab 				start_feed, stop_feed, fei);
161*e7b8153eSMauro Carvalho Chehab 		if (result < 0) {
162*e7b8153eSMauro Carvalho Chehab 			dev_err(fei->dev,
163*e7b8153eSMauro Carvalho Chehab 				"register_dvb feed=%d failed (errno = %d)\n",
164*e7b8153eSMauro Carvalho Chehab 				result, i);
165*e7b8153eSMauro Carvalho Chehab 
166*e7b8153eSMauro Carvalho Chehab 			/* we take a all or nothing approach */
167*e7b8153eSMauro Carvalho Chehab 			for (j = 0; j < i; j++)
168*e7b8153eSMauro Carvalho Chehab 				unregister_dvb(&c8sectpfe->demux[j]);
169*e7b8153eSMauro Carvalho Chehab 			goto err3;
170*e7b8153eSMauro Carvalho Chehab 		}
171*e7b8153eSMauro Carvalho Chehab 	}
172*e7b8153eSMauro Carvalho Chehab 
173*e7b8153eSMauro Carvalho Chehab 	c8sectpfe->num_feeds = fei->tsin_count;
174*e7b8153eSMauro Carvalho Chehab 
175*e7b8153eSMauro Carvalho Chehab 	return c8sectpfe;
176*e7b8153eSMauro Carvalho Chehab err3:
177*e7b8153eSMauro Carvalho Chehab 	dvb_unregister_adapter(&c8sectpfe->adapter);
178*e7b8153eSMauro Carvalho Chehab err2:
179*e7b8153eSMauro Carvalho Chehab 	kfree(c8sectpfe);
180*e7b8153eSMauro Carvalho Chehab err1:
181*e7b8153eSMauro Carvalho Chehab 	return NULL;
182*e7b8153eSMauro Carvalho Chehab };
183*e7b8153eSMauro Carvalho Chehab 
c8sectpfe_delete(struct c8sectpfe * c8sectpfe)184*e7b8153eSMauro Carvalho Chehab static void c8sectpfe_delete(struct c8sectpfe *c8sectpfe)
185*e7b8153eSMauro Carvalho Chehab {
186*e7b8153eSMauro Carvalho Chehab 	int i;
187*e7b8153eSMauro Carvalho Chehab 
188*e7b8153eSMauro Carvalho Chehab 	if (!c8sectpfe)
189*e7b8153eSMauro Carvalho Chehab 		return;
190*e7b8153eSMauro Carvalho Chehab 
191*e7b8153eSMauro Carvalho Chehab 	for (i = 0; i < c8sectpfe->num_feeds; i++)
192*e7b8153eSMauro Carvalho Chehab 		unregister_dvb(&c8sectpfe->demux[i]);
193*e7b8153eSMauro Carvalho Chehab 
194*e7b8153eSMauro Carvalho Chehab 	dvb_unregister_adapter(&c8sectpfe->adapter);
195*e7b8153eSMauro Carvalho Chehab 
196*e7b8153eSMauro Carvalho Chehab 	kfree(c8sectpfe);
197*e7b8153eSMauro Carvalho Chehab };
198*e7b8153eSMauro Carvalho Chehab 
c8sectpfe_tuner_unregister_frontend(struct c8sectpfe * c8sectpfe,struct c8sectpfei * fei)199*e7b8153eSMauro Carvalho Chehab void c8sectpfe_tuner_unregister_frontend(struct c8sectpfe *c8sectpfe,
200*e7b8153eSMauro Carvalho Chehab 					struct c8sectpfei *fei)
201*e7b8153eSMauro Carvalho Chehab {
202*e7b8153eSMauro Carvalho Chehab 	int n;
203*e7b8153eSMauro Carvalho Chehab 	struct channel_info *tsin;
204*e7b8153eSMauro Carvalho Chehab 
205*e7b8153eSMauro Carvalho Chehab 	for (n = 0; n < fei->tsin_count; n++) {
206*e7b8153eSMauro Carvalho Chehab 
207*e7b8153eSMauro Carvalho Chehab 		tsin = fei->channel_data[n];
208*e7b8153eSMauro Carvalho Chehab 
209*e7b8153eSMauro Carvalho Chehab 		if (tsin) {
210*e7b8153eSMauro Carvalho Chehab 			if (tsin->frontend) {
211*e7b8153eSMauro Carvalho Chehab 				dvb_unregister_frontend(tsin->frontend);
212*e7b8153eSMauro Carvalho Chehab 				dvb_frontend_detach(tsin->frontend);
213*e7b8153eSMauro Carvalho Chehab 			}
214*e7b8153eSMauro Carvalho Chehab 
215*e7b8153eSMauro Carvalho Chehab 			i2c_put_adapter(tsin->i2c_adapter);
216*e7b8153eSMauro Carvalho Chehab 
217*e7b8153eSMauro Carvalho Chehab 			if (tsin->i2c_client) {
218*e7b8153eSMauro Carvalho Chehab 				module_put(tsin->i2c_client->dev.driver->owner);
219*e7b8153eSMauro Carvalho Chehab 				i2c_unregister_device(tsin->i2c_client);
220*e7b8153eSMauro Carvalho Chehab 			}
221*e7b8153eSMauro Carvalho Chehab 		}
222*e7b8153eSMauro Carvalho Chehab 	}
223*e7b8153eSMauro Carvalho Chehab 
224*e7b8153eSMauro Carvalho Chehab 	c8sectpfe_delete(c8sectpfe);
225*e7b8153eSMauro Carvalho Chehab };
226*e7b8153eSMauro Carvalho Chehab 
c8sectpfe_tuner_register_frontend(struct c8sectpfe ** c8sectpfe,struct c8sectpfei * fei,void * start_feed,void * stop_feed)227*e7b8153eSMauro Carvalho Chehab int c8sectpfe_tuner_register_frontend(struct c8sectpfe **c8sectpfe,
228*e7b8153eSMauro Carvalho Chehab 				struct c8sectpfei *fei,
229*e7b8153eSMauro Carvalho Chehab 				void *start_feed,
230*e7b8153eSMauro Carvalho Chehab 				void *stop_feed)
231*e7b8153eSMauro Carvalho Chehab {
232*e7b8153eSMauro Carvalho Chehab 	struct channel_info *tsin;
233*e7b8153eSMauro Carvalho Chehab 	struct dvb_frontend *frontend;
234*e7b8153eSMauro Carvalho Chehab 	int n, res;
235*e7b8153eSMauro Carvalho Chehab 
236*e7b8153eSMauro Carvalho Chehab 	*c8sectpfe = c8sectpfe_create(fei, start_feed, stop_feed);
237*e7b8153eSMauro Carvalho Chehab 	if (!*c8sectpfe)
238*e7b8153eSMauro Carvalho Chehab 		return -ENOMEM;
239*e7b8153eSMauro Carvalho Chehab 
240*e7b8153eSMauro Carvalho Chehab 	for (n = 0; n < fei->tsin_count; n++) {
241*e7b8153eSMauro Carvalho Chehab 		tsin = fei->channel_data[n];
242*e7b8153eSMauro Carvalho Chehab 
243*e7b8153eSMauro Carvalho Chehab 		res = c8sectpfe_frontend_attach(&frontend, *c8sectpfe, tsin, n);
244*e7b8153eSMauro Carvalho Chehab 		if (res)
245*e7b8153eSMauro Carvalho Chehab 			goto err;
246*e7b8153eSMauro Carvalho Chehab 
247*e7b8153eSMauro Carvalho Chehab 		res = dvb_register_frontend(&c8sectpfe[0]->adapter, frontend);
248*e7b8153eSMauro Carvalho Chehab 		if (res < 0) {
249*e7b8153eSMauro Carvalho Chehab 			dev_err(fei->dev, "dvb_register_frontend failed (%d)\n",
250*e7b8153eSMauro Carvalho Chehab 				res);
251*e7b8153eSMauro Carvalho Chehab 			goto err;
252*e7b8153eSMauro Carvalho Chehab 		}
253*e7b8153eSMauro Carvalho Chehab 
254*e7b8153eSMauro Carvalho Chehab 		tsin->frontend = frontend;
255*e7b8153eSMauro Carvalho Chehab 	}
256*e7b8153eSMauro Carvalho Chehab 
257*e7b8153eSMauro Carvalho Chehab 	return 0;
258*e7b8153eSMauro Carvalho Chehab 
259*e7b8153eSMauro Carvalho Chehab err:
260*e7b8153eSMauro Carvalho Chehab 	c8sectpfe_tuner_unregister_frontend(*c8sectpfe, fei);
261*e7b8153eSMauro Carvalho Chehab 	return res;
262*e7b8153eSMauro Carvalho Chehab }
263