1// SPDX-License-Identifier: GPL-2.0-or-later
2  /*
3     Driver for ST STB6000 DVBS Silicon tuner
4
5     Copyright (C) 2008 Igor M. Liplianin (liplianin@me.by)
6
7
8  */
9
10#include <linux/slab.h>
11#include <linux/module.h>
12#include <linux/dvb/frontend.h>
13#include <asm/types.h>
14
15#include "stb6000.h"
16
17static int debug;
18#define dprintk(args...) \
19	do { \
20		if (debug) \
21			printk(KERN_DEBUG "stb6000: " args); \
22	} while (0)
23
24struct stb6000_priv {
25	/* i2c details */
26	int i2c_address;
27	struct i2c_adapter *i2c;
28	u32 frequency;
29};
30
31static void stb6000_release(struct dvb_frontend *fe)
32{
33	kfree(fe->tuner_priv);
34	fe->tuner_priv = NULL;
35}
36
37static int stb6000_sleep(struct dvb_frontend *fe)
38{
39	struct stb6000_priv *priv = fe->tuner_priv;
40	int ret;
41	u8 buf[] = { 10, 0 };
42	struct i2c_msg msg = {
43		.addr = priv->i2c_address,
44		.flags = 0,
45		.buf = buf,
46		.len = 2
47	};
48
49	dprintk("%s:\n", __func__);
50
51	if (fe->ops.i2c_gate_ctrl)
52		fe->ops.i2c_gate_ctrl(fe, 1);
53
54	ret = i2c_transfer(priv->i2c, &msg, 1);
55	if (ret != 1)
56		dprintk("%s: i2c error\n", __func__);
57
58	if (fe->ops.i2c_gate_ctrl)
59		fe->ops.i2c_gate_ctrl(fe, 0);
60
61	return (ret == 1) ? 0 : ret;
62}
63
64static int stb6000_set_params(struct dvb_frontend *fe)
65{
66	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
67	struct stb6000_priv *priv = fe->tuner_priv;
68	unsigned int n, m;
69	int ret;
70	u32 freq_mhz;
71	int bandwidth;
72	u8 buf[12];
73	struct i2c_msg msg = {
74		.addr = priv->i2c_address,
75		.flags = 0,
76		.buf = buf,
77		.len = 12
78	};
79
80	dprintk("%s:\n", __func__);
81
82	freq_mhz = p->frequency / 1000;
83	bandwidth = p->symbol_rate / 1000000;
84
85	if (bandwidth > 31)
86		bandwidth = 31;
87
88	if ((freq_mhz > 949) && (freq_mhz < 2151)) {
89		buf[0] = 0x01;
90		buf[1] = 0xac;
91		if (freq_mhz < 1950)
92			buf[1] = 0xaa;
93		if (freq_mhz < 1800)
94			buf[1] = 0xa8;
95		if (freq_mhz < 1650)
96			buf[1] = 0xa6;
97		if (freq_mhz < 1530)
98			buf[1] = 0xa5;
99		if (freq_mhz < 1470)
100			buf[1] = 0xa4;
101		if (freq_mhz < 1370)
102			buf[1] = 0xa2;
103		if (freq_mhz < 1300)
104			buf[1] = 0xa1;
105		if (freq_mhz < 1200)
106			buf[1] = 0xa0;
107		if (freq_mhz < 1075)
108			buf[1] = 0xbc;
109		if (freq_mhz < 1000)
110			buf[1] = 0xba;
111		if (freq_mhz < 1075) {
112			n = freq_mhz / 8; /* vco=lo*4 */
113			m = 2;
114		} else {
115			n = freq_mhz / 16; /* vco=lo*2 */
116			m = 1;
117		}
118		buf[2] = n >> 1;
119		buf[3] = (unsigned char)(((n & 1) << 7) |
120					(m * freq_mhz - n * 16) | 0x60);
121		buf[4] = 0x04;
122		buf[5] = 0x0e;
123
124		buf[6] = (unsigned char)(bandwidth);
125
126		buf[7] = 0xd8;
127		buf[8] = 0xd0;
128		buf[9] = 0x50;
129		buf[10] = 0xeb;
130		buf[11] = 0x4f;
131
132		if (fe->ops.i2c_gate_ctrl)
133			fe->ops.i2c_gate_ctrl(fe, 1);
134
135		ret = i2c_transfer(priv->i2c, &msg, 1);
136		if (ret != 1)
137			dprintk("%s: i2c error\n", __func__);
138
139		udelay(10);
140		if (fe->ops.i2c_gate_ctrl)
141			fe->ops.i2c_gate_ctrl(fe, 0);
142
143		buf[0] = 0x07;
144		buf[1] = 0xdf;
145		buf[2] = 0xd0;
146		buf[3] = 0x50;
147		buf[4] = 0xfb;
148		msg.len = 5;
149
150		if (fe->ops.i2c_gate_ctrl)
151			fe->ops.i2c_gate_ctrl(fe, 1);
152
153		ret = i2c_transfer(priv->i2c, &msg, 1);
154		if (ret != 1)
155			dprintk("%s: i2c error\n", __func__);
156
157		udelay(10);
158		if (fe->ops.i2c_gate_ctrl)
159			fe->ops.i2c_gate_ctrl(fe, 0);
160
161		priv->frequency = freq_mhz * 1000;
162
163		return (ret == 1) ? 0 : ret;
164	}
165	return -1;
166}
167
168static int stb6000_get_frequency(struct dvb_frontend *fe, u32 *frequency)
169{
170	struct stb6000_priv *priv = fe->tuner_priv;
171	*frequency = priv->frequency;
172	return 0;
173}
174
175static const struct dvb_tuner_ops stb6000_tuner_ops = {
176	.info = {
177		.name = "ST STB6000",
178		.frequency_min_hz =  950 * MHz,
179		.frequency_max_hz = 2150 * MHz
180	},
181	.release = stb6000_release,
182	.sleep = stb6000_sleep,
183	.set_params = stb6000_set_params,
184	.get_frequency = stb6000_get_frequency,
185};
186
187struct dvb_frontend *stb6000_attach(struct dvb_frontend *fe, int addr,
188						struct i2c_adapter *i2c)
189{
190	struct stb6000_priv *priv = NULL;
191	u8 b0[] = { 0 };
192	u8 b1[] = { 0, 0 };
193	struct i2c_msg msg[2] = {
194		{
195			.addr = addr,
196			.flags = 0,
197			.buf = b0,
198			.len = 0
199		}, {
200			.addr = addr,
201			.flags = I2C_M_RD,
202			.buf = b1,
203			.len = 2
204		}
205	};
206	int ret;
207
208	dprintk("%s:\n", __func__);
209
210	if (fe->ops.i2c_gate_ctrl)
211		fe->ops.i2c_gate_ctrl(fe, 1);
212
213	/* is some i2c device here ? */
214	ret = i2c_transfer(i2c, msg, 2);
215	if (fe->ops.i2c_gate_ctrl)
216		fe->ops.i2c_gate_ctrl(fe, 0);
217
218	if (ret != 2)
219		return NULL;
220
221	priv = kzalloc(sizeof(struct stb6000_priv), GFP_KERNEL);
222	if (priv == NULL)
223		return NULL;
224
225	priv->i2c_address = addr;
226	priv->i2c = i2c;
227
228	memcpy(&fe->ops.tuner_ops, &stb6000_tuner_ops,
229				sizeof(struct dvb_tuner_ops));
230
231	fe->tuner_priv = priv;
232
233	return fe;
234}
235EXPORT_SYMBOL_GPL(stb6000_attach);
236
237module_param(debug, int, 0644);
238MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
239
240MODULE_DESCRIPTION("DVB STB6000 driver");
241MODULE_AUTHOR("Igor M. Liplianin <liplianin@me.by>");
242MODULE_LICENSE("GPL");
243