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