xref: /OK3568_Linux_fs/kernel/drivers/media/tuners/tua9001.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Infineon TUA9001 silicon tuner driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include "tua9001_priv.h"
9*4882a593Smuzhiyun 
tua9001_init(struct dvb_frontend * fe)10*4882a593Smuzhiyun static int tua9001_init(struct dvb_frontend *fe)
11*4882a593Smuzhiyun {
12*4882a593Smuzhiyun 	struct tua9001_dev *dev = fe->tuner_priv;
13*4882a593Smuzhiyun 	struct i2c_client *client = dev->client;
14*4882a593Smuzhiyun 	int ret, i;
15*4882a593Smuzhiyun 	static const struct tua9001_reg_val data[] = {
16*4882a593Smuzhiyun 		{0x1e, 0x6512},
17*4882a593Smuzhiyun 		{0x25, 0xb888},
18*4882a593Smuzhiyun 		{0x39, 0x5460},
19*4882a593Smuzhiyun 		{0x3b, 0x00c0},
20*4882a593Smuzhiyun 		{0x3a, 0xf000},
21*4882a593Smuzhiyun 		{0x08, 0x0000},
22*4882a593Smuzhiyun 		{0x32, 0x0030},
23*4882a593Smuzhiyun 		{0x41, 0x703a},
24*4882a593Smuzhiyun 		{0x40, 0x1c78},
25*4882a593Smuzhiyun 		{0x2c, 0x1c00},
26*4882a593Smuzhiyun 		{0x36, 0xc013},
27*4882a593Smuzhiyun 		{0x37, 0x6f18},
28*4882a593Smuzhiyun 		{0x27, 0x0008},
29*4882a593Smuzhiyun 		{0x2a, 0x0001},
30*4882a593Smuzhiyun 		{0x34, 0x0a40},
31*4882a593Smuzhiyun 	};
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun 	dev_dbg(&client->dev, "\n");
34*4882a593Smuzhiyun 
35*4882a593Smuzhiyun 	if (fe->callback) {
36*4882a593Smuzhiyun 		ret = fe->callback(client->adapter,
37*4882a593Smuzhiyun 				   DVB_FRONTEND_COMPONENT_TUNER,
38*4882a593Smuzhiyun 				   TUA9001_CMD_RESETN, 0);
39*4882a593Smuzhiyun 		if (ret)
40*4882a593Smuzhiyun 			goto err;
41*4882a593Smuzhiyun 	}
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(data); i++) {
44*4882a593Smuzhiyun 		ret = regmap_write(dev->regmap, data[i].reg, data[i].val);
45*4882a593Smuzhiyun 		if (ret)
46*4882a593Smuzhiyun 			goto err;
47*4882a593Smuzhiyun 	}
48*4882a593Smuzhiyun 	return 0;
49*4882a593Smuzhiyun err:
50*4882a593Smuzhiyun 	dev_dbg(&client->dev, "failed=%d\n", ret);
51*4882a593Smuzhiyun 	return ret;
52*4882a593Smuzhiyun }
53*4882a593Smuzhiyun 
tua9001_sleep(struct dvb_frontend * fe)54*4882a593Smuzhiyun static int tua9001_sleep(struct dvb_frontend *fe)
55*4882a593Smuzhiyun {
56*4882a593Smuzhiyun 	struct tua9001_dev *dev = fe->tuner_priv;
57*4882a593Smuzhiyun 	struct i2c_client *client = dev->client;
58*4882a593Smuzhiyun 	int ret;
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun 	dev_dbg(&client->dev, "\n");
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	if (fe->callback) {
63*4882a593Smuzhiyun 		ret = fe->callback(client->adapter,
64*4882a593Smuzhiyun 				   DVB_FRONTEND_COMPONENT_TUNER,
65*4882a593Smuzhiyun 				   TUA9001_CMD_RESETN, 1);
66*4882a593Smuzhiyun 		if (ret)
67*4882a593Smuzhiyun 			goto err;
68*4882a593Smuzhiyun 	}
69*4882a593Smuzhiyun 	return 0;
70*4882a593Smuzhiyun err:
71*4882a593Smuzhiyun 	dev_dbg(&client->dev, "failed=%d\n", ret);
72*4882a593Smuzhiyun 	return ret;
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun 
tua9001_set_params(struct dvb_frontend * fe)75*4882a593Smuzhiyun static int tua9001_set_params(struct dvb_frontend *fe)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun 	struct tua9001_dev *dev = fe->tuner_priv;
78*4882a593Smuzhiyun 	struct i2c_client *client = dev->client;
79*4882a593Smuzhiyun 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
80*4882a593Smuzhiyun 	int ret, i;
81*4882a593Smuzhiyun 	u16 val;
82*4882a593Smuzhiyun 	struct tua9001_reg_val data[2];
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	dev_dbg(&client->dev,
85*4882a593Smuzhiyun 		"delivery_system=%u frequency=%u bandwidth_hz=%u\n",
86*4882a593Smuzhiyun 		c->delivery_system, c->frequency, c->bandwidth_hz);
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun 	switch (c->delivery_system) {
89*4882a593Smuzhiyun 	case SYS_DVBT:
90*4882a593Smuzhiyun 		switch (c->bandwidth_hz) {
91*4882a593Smuzhiyun 		case 8000000:
92*4882a593Smuzhiyun 			val  = 0x0000;
93*4882a593Smuzhiyun 			break;
94*4882a593Smuzhiyun 		case 7000000:
95*4882a593Smuzhiyun 			val  = 0x1000;
96*4882a593Smuzhiyun 			break;
97*4882a593Smuzhiyun 		case 6000000:
98*4882a593Smuzhiyun 			val  = 0x2000;
99*4882a593Smuzhiyun 			break;
100*4882a593Smuzhiyun 		case 5000000:
101*4882a593Smuzhiyun 			val  = 0x3000;
102*4882a593Smuzhiyun 			break;
103*4882a593Smuzhiyun 		default:
104*4882a593Smuzhiyun 			ret = -EINVAL;
105*4882a593Smuzhiyun 			goto err;
106*4882a593Smuzhiyun 		}
107*4882a593Smuzhiyun 		break;
108*4882a593Smuzhiyun 	default:
109*4882a593Smuzhiyun 		ret = -EINVAL;
110*4882a593Smuzhiyun 		goto err;
111*4882a593Smuzhiyun 	}
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	data[0].reg = 0x04;
114*4882a593Smuzhiyun 	data[0].val = val;
115*4882a593Smuzhiyun 	data[1].reg = 0x1f;
116*4882a593Smuzhiyun 	data[1].val = div_u64((u64) (c->frequency - 150000000) * 48, 1000000);
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	if (fe->callback) {
119*4882a593Smuzhiyun 		ret = fe->callback(client->adapter,
120*4882a593Smuzhiyun 				   DVB_FRONTEND_COMPONENT_TUNER,
121*4882a593Smuzhiyun 				   TUA9001_CMD_RXEN, 0);
122*4882a593Smuzhiyun 		if (ret)
123*4882a593Smuzhiyun 			goto err;
124*4882a593Smuzhiyun 	}
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(data); i++) {
127*4882a593Smuzhiyun 		ret = regmap_write(dev->regmap, data[i].reg, data[i].val);
128*4882a593Smuzhiyun 		if (ret)
129*4882a593Smuzhiyun 			goto err;
130*4882a593Smuzhiyun 	}
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	if (fe->callback) {
133*4882a593Smuzhiyun 		ret = fe->callback(client->adapter,
134*4882a593Smuzhiyun 				   DVB_FRONTEND_COMPONENT_TUNER,
135*4882a593Smuzhiyun 				   TUA9001_CMD_RXEN, 1);
136*4882a593Smuzhiyun 		if (ret)
137*4882a593Smuzhiyun 			goto err;
138*4882a593Smuzhiyun 	}
139*4882a593Smuzhiyun 	return 0;
140*4882a593Smuzhiyun err:
141*4882a593Smuzhiyun 	dev_dbg(&client->dev, "failed=%d\n", ret);
142*4882a593Smuzhiyun 	return ret;
143*4882a593Smuzhiyun }
144*4882a593Smuzhiyun 
tua9001_get_if_frequency(struct dvb_frontend * fe,u32 * frequency)145*4882a593Smuzhiyun static int tua9001_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun 	struct tua9001_dev *dev = fe->tuner_priv;
148*4882a593Smuzhiyun 	struct i2c_client *client = dev->client;
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	dev_dbg(&client->dev, "\n");
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	*frequency = 0; /* Zero-IF */
153*4882a593Smuzhiyun 	return 0;
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun static const struct dvb_tuner_ops tua9001_tuner_ops = {
157*4882a593Smuzhiyun 	.info = {
158*4882a593Smuzhiyun 		.name             = "Infineon TUA9001",
159*4882a593Smuzhiyun 		.frequency_min_hz = 170 * MHz,
160*4882a593Smuzhiyun 		.frequency_max_hz = 862 * MHz,
161*4882a593Smuzhiyun 	},
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	.init = tua9001_init,
164*4882a593Smuzhiyun 	.sleep = tua9001_sleep,
165*4882a593Smuzhiyun 	.set_params = tua9001_set_params,
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	.get_if_frequency = tua9001_get_if_frequency,
168*4882a593Smuzhiyun };
169*4882a593Smuzhiyun 
tua9001_probe(struct i2c_client * client,const struct i2c_device_id * id)170*4882a593Smuzhiyun static int tua9001_probe(struct i2c_client *client,
171*4882a593Smuzhiyun 			const struct i2c_device_id *id)
172*4882a593Smuzhiyun {
173*4882a593Smuzhiyun 	struct tua9001_dev *dev;
174*4882a593Smuzhiyun 	struct tua9001_platform_data *pdata = client->dev.platform_data;
175*4882a593Smuzhiyun 	struct dvb_frontend *fe = pdata->dvb_frontend;
176*4882a593Smuzhiyun 	int ret;
177*4882a593Smuzhiyun 	static const struct regmap_config regmap_config = {
178*4882a593Smuzhiyun 		.reg_bits =  8,
179*4882a593Smuzhiyun 		.val_bits = 16,
180*4882a593Smuzhiyun 	};
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
183*4882a593Smuzhiyun 	if (!dev) {
184*4882a593Smuzhiyun 		ret = -ENOMEM;
185*4882a593Smuzhiyun 		goto err;
186*4882a593Smuzhiyun 	}
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	dev->fe = pdata->dvb_frontend;
189*4882a593Smuzhiyun 	dev->client = client;
190*4882a593Smuzhiyun 	dev->regmap = devm_regmap_init_i2c(client, &regmap_config);
191*4882a593Smuzhiyun 	if (IS_ERR(dev->regmap)) {
192*4882a593Smuzhiyun 		ret = PTR_ERR(dev->regmap);
193*4882a593Smuzhiyun 		goto err_kfree;
194*4882a593Smuzhiyun 	}
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	if (fe->callback) {
197*4882a593Smuzhiyun 		ret = fe->callback(client->adapter,
198*4882a593Smuzhiyun 				   DVB_FRONTEND_COMPONENT_TUNER,
199*4882a593Smuzhiyun 				   TUA9001_CMD_CEN, 1);
200*4882a593Smuzhiyun 		if (ret)
201*4882a593Smuzhiyun 			goto err_kfree;
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 		ret = fe->callback(client->adapter,
204*4882a593Smuzhiyun 				   DVB_FRONTEND_COMPONENT_TUNER,
205*4882a593Smuzhiyun 				   TUA9001_CMD_RXEN, 0);
206*4882a593Smuzhiyun 		if (ret)
207*4882a593Smuzhiyun 			goto err_kfree;
208*4882a593Smuzhiyun 
209*4882a593Smuzhiyun 		ret = fe->callback(client->adapter,
210*4882a593Smuzhiyun 				   DVB_FRONTEND_COMPONENT_TUNER,
211*4882a593Smuzhiyun 				   TUA9001_CMD_RESETN, 1);
212*4882a593Smuzhiyun 		if (ret)
213*4882a593Smuzhiyun 			goto err_kfree;
214*4882a593Smuzhiyun 	}
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	fe->tuner_priv = dev;
217*4882a593Smuzhiyun 	memcpy(&fe->ops.tuner_ops, &tua9001_tuner_ops,
218*4882a593Smuzhiyun 			sizeof(struct dvb_tuner_ops));
219*4882a593Smuzhiyun 	i2c_set_clientdata(client, dev);
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	dev_info(&client->dev, "Infineon TUA9001 successfully attached\n");
222*4882a593Smuzhiyun 	return 0;
223*4882a593Smuzhiyun err_kfree:
224*4882a593Smuzhiyun 	kfree(dev);
225*4882a593Smuzhiyun err:
226*4882a593Smuzhiyun 	dev_dbg(&client->dev, "failed=%d\n", ret);
227*4882a593Smuzhiyun 	return ret;
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun 
tua9001_remove(struct i2c_client * client)230*4882a593Smuzhiyun static int tua9001_remove(struct i2c_client *client)
231*4882a593Smuzhiyun {
232*4882a593Smuzhiyun 	struct tua9001_dev *dev = i2c_get_clientdata(client);
233*4882a593Smuzhiyun 	struct dvb_frontend *fe = dev->fe;
234*4882a593Smuzhiyun 	int ret;
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	dev_dbg(&client->dev, "\n");
237*4882a593Smuzhiyun 
238*4882a593Smuzhiyun 	if (fe->callback) {
239*4882a593Smuzhiyun 		ret = fe->callback(client->adapter,
240*4882a593Smuzhiyun 				   DVB_FRONTEND_COMPONENT_TUNER,
241*4882a593Smuzhiyun 				   TUA9001_CMD_CEN, 0);
242*4882a593Smuzhiyun 		if (ret)
243*4882a593Smuzhiyun 			goto err_kfree;
244*4882a593Smuzhiyun 	}
245*4882a593Smuzhiyun 	kfree(dev);
246*4882a593Smuzhiyun 	return 0;
247*4882a593Smuzhiyun err_kfree:
248*4882a593Smuzhiyun 	kfree(dev);
249*4882a593Smuzhiyun 	dev_dbg(&client->dev, "failed=%d\n", ret);
250*4882a593Smuzhiyun 	return ret;
251*4882a593Smuzhiyun }
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun static const struct i2c_device_id tua9001_id_table[] = {
254*4882a593Smuzhiyun 	{"tua9001", 0},
255*4882a593Smuzhiyun 	{}
256*4882a593Smuzhiyun };
257*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, tua9001_id_table);
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun static struct i2c_driver tua9001_driver = {
260*4882a593Smuzhiyun 	.driver = {
261*4882a593Smuzhiyun 		.name	= "tua9001",
262*4882a593Smuzhiyun 		.suppress_bind_attrs = true,
263*4882a593Smuzhiyun 	},
264*4882a593Smuzhiyun 	.probe		= tua9001_probe,
265*4882a593Smuzhiyun 	.remove		= tua9001_remove,
266*4882a593Smuzhiyun 	.id_table	= tua9001_id_table,
267*4882a593Smuzhiyun };
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun module_i2c_driver(tua9001_driver);
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun MODULE_DESCRIPTION("Infineon TUA9001 silicon tuner driver");
272*4882a593Smuzhiyun MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
273*4882a593Smuzhiyun MODULE_LICENSE("GPL");
274