GNU Linux-libre 5.19-rc6-gnu
[releases.git] / drivers / media / pci / mantis / mantis_vp1033.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3         Mantis VP-1033 driver
4
5         Copyright (C) Manu Abraham (abraham.manu@gmail.com)
6
7 */
8
9 #include <linux/signal.h>
10 #include <linux/sched.h>
11 #include <linux/interrupt.h>
12
13 #include <media/dmxdev.h>
14 #include <media/dvbdev.h>
15 #include <media/dvb_demux.h>
16 #include <media/dvb_frontend.h>
17 #include <media/dvb_net.h>
18
19 #include "stv0299.h"
20 #include "mantis_common.h"
21 #include "mantis_ioc.h"
22 #include "mantis_dvb.h"
23 #include "mantis_vp1033.h"
24 #include "mantis_reg.h"
25
26 static u8 lgtdqcs001f_inittab[] = {
27         0x01, 0x15,
28         0x02, 0x30,
29         0x03, 0x00,
30         0x04, 0x2a,
31         0x05, 0x85,
32         0x06, 0x02,
33         0x07, 0x00,
34         0x08, 0x00,
35         0x0c, 0x01,
36         0x0d, 0x81,
37         0x0e, 0x44,
38         0x0f, 0x94,
39         0x10, 0x3c,
40         0x11, 0x84,
41         0x12, 0xb9,
42         0x13, 0xb5,
43         0x14, 0x4f,
44         0x15, 0xc9,
45         0x16, 0x80,
46         0x17, 0x36,
47         0x18, 0xfb,
48         0x19, 0xcf,
49         0x1a, 0xbc,
50         0x1c, 0x2b,
51         0x1d, 0x27,
52         0x1e, 0x00,
53         0x1f, 0x0b,
54         0x20, 0xa1,
55         0x21, 0x60,
56         0x22, 0x00,
57         0x23, 0x00,
58         0x28, 0x00,
59         0x29, 0x28,
60         0x2a, 0x14,
61         0x2b, 0x0f,
62         0x2c, 0x09,
63         0x2d, 0x05,
64         0x31, 0x1f,
65         0x32, 0x19,
66         0x33, 0xfc,
67         0x34, 0x13,
68         0xff, 0xff,
69 };
70
71 #define MANTIS_MODEL_NAME       "VP-1033"
72 #define MANTIS_DEV_TYPE         "DVB-S/DSS"
73
74 static int lgtdqcs001f_tuner_set(struct dvb_frontend *fe)
75 {
76         struct dtv_frontend_properties *p = &fe->dtv_property_cache;
77         struct mantis_pci *mantis       = fe->dvb->priv;
78         struct i2c_adapter *adapter     = &mantis->adapter;
79
80         u8 buf[4];
81         u32 div;
82
83
84         struct i2c_msg msg = {.addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf)};
85
86         div = p->frequency / 250;
87
88         buf[0] = (div >> 8) & 0x7f;
89         buf[1] =  div & 0xff;
90         buf[2] =  0x83;
91         buf[3] =  0xc0;
92
93         if (p->frequency < 1531000)
94                 buf[3] |= 0x04;
95         else
96                 buf[3] &= ~0x04;
97         if (i2c_transfer(adapter, &msg, 1) < 0) {
98                 dprintk(MANTIS_ERROR, 1, "Write: I2C Transfer failed");
99                 return -EIO;
100         }
101         msleep_interruptible(100);
102
103         return 0;
104 }
105
106 static int lgtdqcs001f_set_symbol_rate(struct dvb_frontend *fe,
107                                        u32 srate, u32 ratio)
108 {
109         u8 aclk = 0;
110         u8 bclk = 0;
111
112         if (srate < 1500000) {
113                 aclk = 0xb7;
114                 bclk = 0x47;
115         } else if (srate < 3000000) {
116                 aclk = 0xb7;
117                 bclk = 0x4b;
118         } else if (srate < 7000000) {
119                 aclk = 0xb7;
120                 bclk = 0x4f;
121         } else if (srate < 14000000) {
122                 aclk = 0xb7;
123                 bclk = 0x53;
124         } else if (srate < 30000000) {
125                 aclk = 0xb6;
126                 bclk = 0x53;
127         } else if (srate < 45000000) {
128                 aclk = 0xb4;
129                 bclk = 0x51;
130         }
131         stv0299_writereg(fe, 0x13, aclk);
132         stv0299_writereg(fe, 0x14, bclk);
133
134         stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
135         stv0299_writereg(fe, 0x20, (ratio >>  8) & 0xff);
136         stv0299_writereg(fe, 0x21,  ratio & 0xf0);
137
138         return 0;
139 }
140
141 static struct stv0299_config lgtdqcs001f_config = {
142         .demod_address          = 0x68,
143         .inittab                = lgtdqcs001f_inittab,
144         .mclk                   = 88000000UL,
145         .invert                 = 0,
146         .skip_reinit            = 0,
147         .volt13_op0_op1         = STV0299_VOLT13_OP0,
148         .min_delay_ms           = 100,
149         .set_symbol_rate        = lgtdqcs001f_set_symbol_rate,
150 };
151
152 static int vp1033_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *fe)
153 {
154         struct i2c_adapter *adapter     = &mantis->adapter;
155
156         int err = 0;
157
158         err = mantis_frontend_power(mantis, POWER_ON);
159         if (err == 0) {
160                 mantis_frontend_soft_reset(mantis);
161                 msleep(250);
162
163                 dprintk(MANTIS_ERROR, 1, "Probing for STV0299 (DVB-S)");
164                 fe = dvb_attach(stv0299_attach, &lgtdqcs001f_config, adapter);
165
166                 if (fe) {
167                         fe->ops.tuner_ops.set_params = lgtdqcs001f_tuner_set;
168                         dprintk(MANTIS_ERROR, 1, "found STV0299 DVB-S frontend @ 0x%02x",
169                                 lgtdqcs001f_config.demod_address);
170
171                         dprintk(MANTIS_ERROR, 1, "Mantis DVB-S STV0299 frontend attach success");
172                 } else {
173                         return -1;
174                 }
175         } else {
176                 dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
177                         adapter->name,
178                         err);
179
180                 return -EIO;
181         }
182         mantis->fe = fe;
183         dprintk(MANTIS_ERROR, 1, "Done!");
184
185         return 0;
186 }
187
188 struct mantis_hwconfig vp1033_config = {
189         .model_name             = MANTIS_MODEL_NAME,
190         .dev_type               = MANTIS_DEV_TYPE,
191         .ts_size                = MANTIS_TS_204,
192
193         .baud_rate              = MANTIS_BAUD_9600,
194         .parity                 = MANTIS_PARITY_NONE,
195         .bytes                  = 0,
196
197         .frontend_init          = vp1033_frontend_init,
198         .power                  = GPIF_A12,
199         .reset                  = GPIF_A13,
200 };