xref: /openbmc/linux/drivers/media/tuners/tua9001.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2ccae7af2SMauro Carvalho Chehab /*
3ccae7af2SMauro Carvalho Chehab  * Infineon TUA9001 silicon tuner driver
4ccae7af2SMauro Carvalho Chehab  *
5ccae7af2SMauro Carvalho Chehab  * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
6ccae7af2SMauro Carvalho Chehab  */
7ccae7af2SMauro Carvalho Chehab 
8ccae7af2SMauro Carvalho Chehab #include "tua9001_priv.h"
9ccae7af2SMauro Carvalho Chehab 
tua9001_init(struct dvb_frontend * fe)10ccae7af2SMauro Carvalho Chehab static int tua9001_init(struct dvb_frontend *fe)
11ccae7af2SMauro Carvalho Chehab {
12465433faSAntti Palosaari 	struct tua9001_dev *dev = fe->tuner_priv;
13465433faSAntti Palosaari 	struct i2c_client *client = dev->client;
14465433faSAntti Palosaari 	int ret, i;
15465433faSAntti Palosaari 	static const struct tua9001_reg_val data[] = {
16ccae7af2SMauro Carvalho Chehab 		{0x1e, 0x6512},
17ccae7af2SMauro Carvalho Chehab 		{0x25, 0xb888},
18ccae7af2SMauro Carvalho Chehab 		{0x39, 0x5460},
19ccae7af2SMauro Carvalho Chehab 		{0x3b, 0x00c0},
20ccae7af2SMauro Carvalho Chehab 		{0x3a, 0xf000},
21ccae7af2SMauro Carvalho Chehab 		{0x08, 0x0000},
22ccae7af2SMauro Carvalho Chehab 		{0x32, 0x0030},
23ccae7af2SMauro Carvalho Chehab 		{0x41, 0x703a},
24ccae7af2SMauro Carvalho Chehab 		{0x40, 0x1c78},
25ccae7af2SMauro Carvalho Chehab 		{0x2c, 0x1c00},
26ccae7af2SMauro Carvalho Chehab 		{0x36, 0xc013},
27ccae7af2SMauro Carvalho Chehab 		{0x37, 0x6f18},
28ccae7af2SMauro Carvalho Chehab 		{0x27, 0x0008},
29ccae7af2SMauro Carvalho Chehab 		{0x2a, 0x0001},
30ccae7af2SMauro Carvalho Chehab 		{0x34, 0x0a40},
31ccae7af2SMauro Carvalho Chehab 	};
32ccae7af2SMauro Carvalho Chehab 
33465433faSAntti Palosaari 	dev_dbg(&client->dev, "\n");
34e6211c7cSAntti Palosaari 
3589054e37SAntti Palosaari 	if (fe->callback) {
36465433faSAntti Palosaari 		ret = fe->callback(client->adapter,
37465433faSAntti Palosaari 				   DVB_FRONTEND_COMPONENT_TUNER,
3889054e37SAntti Palosaari 				   TUA9001_CMD_RESETN, 0);
39465433faSAntti Palosaari 		if (ret)
4089054e37SAntti Palosaari 			goto err;
4189054e37SAntti Palosaari 	}
4289054e37SAntti Palosaari 
43ccae7af2SMauro Carvalho Chehab 	for (i = 0; i < ARRAY_SIZE(data); i++) {
44dd219a87SAntti Palosaari 		ret = regmap_write(dev->regmap, data[i].reg, data[i].val);
45465433faSAntti Palosaari 		if (ret)
4696676239SAntti Palosaari 			goto err;
47ccae7af2SMauro Carvalho Chehab 	}
48465433faSAntti Palosaari 	return 0;
4989054e37SAntti Palosaari err:
50465433faSAntti Palosaari 	dev_dbg(&client->dev, "failed=%d\n", ret);
5189054e37SAntti Palosaari 	return ret;
5289054e37SAntti Palosaari }
5389054e37SAntti Palosaari 
tua9001_sleep(struct dvb_frontend * fe)5489054e37SAntti Palosaari static int tua9001_sleep(struct dvb_frontend *fe)
5589054e37SAntti Palosaari {
56465433faSAntti Palosaari 	struct tua9001_dev *dev = fe->tuner_priv;
57465433faSAntti Palosaari 	struct i2c_client *client = dev->client;
58465433faSAntti Palosaari 	int ret;
5989054e37SAntti Palosaari 
60465433faSAntti Palosaari 	dev_dbg(&client->dev, "\n");
61e6211c7cSAntti Palosaari 
62465433faSAntti Palosaari 	if (fe->callback) {
63465433faSAntti Palosaari 		ret = fe->callback(client->adapter,
64465433faSAntti Palosaari 				   DVB_FRONTEND_COMPONENT_TUNER,
6589054e37SAntti Palosaari 				   TUA9001_CMD_RESETN, 1);
66465433faSAntti Palosaari 		if (ret)
67465433faSAntti Palosaari 			goto err;
68465433faSAntti Palosaari 	}
69465433faSAntti Palosaari 	return 0;
70465433faSAntti Palosaari err:
71465433faSAntti Palosaari 	dev_dbg(&client->dev, "failed=%d\n", ret);
72ccae7af2SMauro Carvalho Chehab 	return ret;
73ccae7af2SMauro Carvalho Chehab }
74ccae7af2SMauro Carvalho Chehab 
tua9001_set_params(struct dvb_frontend * fe)75ccae7af2SMauro Carvalho Chehab static int tua9001_set_params(struct dvb_frontend *fe)
76ccae7af2SMauro Carvalho Chehab {
77465433faSAntti Palosaari 	struct tua9001_dev *dev = fe->tuner_priv;
78465433faSAntti Palosaari 	struct i2c_client *client = dev->client;
79ccae7af2SMauro Carvalho Chehab 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
80465433faSAntti Palosaari 	int ret, i;
81ccae7af2SMauro Carvalho Chehab 	u16 val;
82465433faSAntti Palosaari 	struct tua9001_reg_val data[2];
83ccae7af2SMauro Carvalho Chehab 
84465433faSAntti Palosaari 	dev_dbg(&client->dev,
85465433faSAntti Palosaari 		"delivery_system=%u frequency=%u bandwidth_hz=%u\n",
86e6211c7cSAntti Palosaari 		c->delivery_system, c->frequency, c->bandwidth_hz);
87ccae7af2SMauro Carvalho Chehab 
88ccae7af2SMauro Carvalho Chehab 	switch (c->delivery_system) {
89ccae7af2SMauro Carvalho Chehab 	case SYS_DVBT:
90ccae7af2SMauro Carvalho Chehab 		switch (c->bandwidth_hz) {
91ccae7af2SMauro Carvalho Chehab 		case 8000000:
92ccae7af2SMauro Carvalho Chehab 			val  = 0x0000;
93ccae7af2SMauro Carvalho Chehab 			break;
94ccae7af2SMauro Carvalho Chehab 		case 7000000:
95ccae7af2SMauro Carvalho Chehab 			val  = 0x1000;
96ccae7af2SMauro Carvalho Chehab 			break;
97ccae7af2SMauro Carvalho Chehab 		case 6000000:
98ccae7af2SMauro Carvalho Chehab 			val  = 0x2000;
99ccae7af2SMauro Carvalho Chehab 			break;
100ccae7af2SMauro Carvalho Chehab 		case 5000000:
101ccae7af2SMauro Carvalho Chehab 			val  = 0x3000;
102ccae7af2SMauro Carvalho Chehab 			break;
103ccae7af2SMauro Carvalho Chehab 		default:
104ccae7af2SMauro Carvalho Chehab 			ret = -EINVAL;
105ccae7af2SMauro Carvalho Chehab 			goto err;
106ccae7af2SMauro Carvalho Chehab 		}
107ccae7af2SMauro Carvalho Chehab 		break;
108ccae7af2SMauro Carvalho Chehab 	default:
109ccae7af2SMauro Carvalho Chehab 		ret = -EINVAL;
110ccae7af2SMauro Carvalho Chehab 		goto err;
111ccae7af2SMauro Carvalho Chehab 	}
112ccae7af2SMauro Carvalho Chehab 
113ccae7af2SMauro Carvalho Chehab 	data[0].reg = 0x04;
114ccae7af2SMauro Carvalho Chehab 	data[0].val = val;
115ccae7af2SMauro Carvalho Chehab 	data[1].reg = 0x1f;
11647f95dbdSAntti Palosaari 	data[1].val = div_u64((u64) (c->frequency - 150000000) * 48, 1000000);
117ccae7af2SMauro Carvalho Chehab 
11889054e37SAntti Palosaari 	if (fe->callback) {
119465433faSAntti Palosaari 		ret = fe->callback(client->adapter,
120465433faSAntti Palosaari 				   DVB_FRONTEND_COMPONENT_TUNER,
12189054e37SAntti Palosaari 				   TUA9001_CMD_RXEN, 0);
122465433faSAntti Palosaari 		if (ret)
12396676239SAntti Palosaari 			goto err;
12489054e37SAntti Palosaari 	}
12589054e37SAntti Palosaari 
126ccae7af2SMauro Carvalho Chehab 	for (i = 0; i < ARRAY_SIZE(data); i++) {
127dd219a87SAntti Palosaari 		ret = regmap_write(dev->regmap, data[i].reg, data[i].val);
128465433faSAntti Palosaari 		if (ret)
12996676239SAntti Palosaari 			goto err;
130ccae7af2SMauro Carvalho Chehab 	}
131ccae7af2SMauro Carvalho Chehab 
13289054e37SAntti Palosaari 	if (fe->callback) {
133465433faSAntti Palosaari 		ret = fe->callback(client->adapter,
134465433faSAntti Palosaari 				   DVB_FRONTEND_COMPONENT_TUNER,
13589054e37SAntti Palosaari 				   TUA9001_CMD_RXEN, 1);
136465433faSAntti Palosaari 		if (ret)
13796676239SAntti Palosaari 			goto err;
13889054e37SAntti Palosaari 	}
139465433faSAntti Palosaari 	return 0;
140ccae7af2SMauro Carvalho Chehab err:
141465433faSAntti Palosaari 	dev_dbg(&client->dev, "failed=%d\n", ret);
142ccae7af2SMauro Carvalho Chehab 	return ret;
143ccae7af2SMauro Carvalho Chehab }
144ccae7af2SMauro Carvalho Chehab 
tua9001_get_if_frequency(struct dvb_frontend * fe,u32 * frequency)145ccae7af2SMauro Carvalho Chehab static int tua9001_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
146ccae7af2SMauro Carvalho Chehab {
147465433faSAntti Palosaari 	struct tua9001_dev *dev = fe->tuner_priv;
148465433faSAntti Palosaari 	struct i2c_client *client = dev->client;
149e6211c7cSAntti Palosaari 
150465433faSAntti Palosaari 	dev_dbg(&client->dev, "\n");
151e6211c7cSAntti Palosaari 
152ccae7af2SMauro Carvalho Chehab 	*frequency = 0; /* Zero-IF */
153ccae7af2SMauro Carvalho Chehab 	return 0;
154ccae7af2SMauro Carvalho Chehab }
155ccae7af2SMauro Carvalho Chehab 
156ccae7af2SMauro Carvalho Chehab static const struct dvb_tuner_ops tua9001_tuner_ops = {
157ccae7af2SMauro Carvalho Chehab 	.info = {
158ccae7af2SMauro Carvalho Chehab 		.name             = "Infineon TUA9001",
159a3f90c75SMauro Carvalho Chehab 		.frequency_min_hz = 170 * MHz,
160a3f90c75SMauro Carvalho Chehab 		.frequency_max_hz = 862 * MHz,
161ccae7af2SMauro Carvalho Chehab 	},
162ccae7af2SMauro Carvalho Chehab 
163ccae7af2SMauro Carvalho Chehab 	.init = tua9001_init,
16489054e37SAntti Palosaari 	.sleep = tua9001_sleep,
165ccae7af2SMauro Carvalho Chehab 	.set_params = tua9001_set_params,
166ccae7af2SMauro Carvalho Chehab 
167ccae7af2SMauro Carvalho Chehab 	.get_if_frequency = tua9001_get_if_frequency,
168ccae7af2SMauro Carvalho Chehab };
169ccae7af2SMauro Carvalho Chehab 
tua9001_probe(struct i2c_client * client)17014fb5516SUwe Kleine-König static int tua9001_probe(struct i2c_client *client)
171fc851c66SAntti Palosaari {
172465433faSAntti Palosaari 	struct tua9001_dev *dev;
173fc851c66SAntti Palosaari 	struct tua9001_platform_data *pdata = client->dev.platform_data;
174fc851c66SAntti Palosaari 	struct dvb_frontend *fe = pdata->dvb_frontend;
175fc851c66SAntti Palosaari 	int ret;
176dd219a87SAntti Palosaari 	static const struct regmap_config regmap_config = {
177dd219a87SAntti Palosaari 		.reg_bits =  8,
178dd219a87SAntti Palosaari 		.val_bits = 16,
179dd219a87SAntti Palosaari 	};
180fc851c66SAntti Palosaari 
181fc851c66SAntti Palosaari 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
182fc851c66SAntti Palosaari 	if (!dev) {
183fc851c66SAntti Palosaari 		ret = -ENOMEM;
184fc851c66SAntti Palosaari 		goto err;
185fc851c66SAntti Palosaari 	}
186fc851c66SAntti Palosaari 
187fc851c66SAntti Palosaari 	dev->fe = pdata->dvb_frontend;
188dd219a87SAntti Palosaari 	dev->client = client;
189dd219a87SAntti Palosaari 	dev->regmap = devm_regmap_init_i2c(client, &regmap_config);
190dd219a87SAntti Palosaari 	if (IS_ERR(dev->regmap)) {
191dd219a87SAntti Palosaari 		ret = PTR_ERR(dev->regmap);
192dd219a87SAntti Palosaari 		goto err_kfree;
193dd219a87SAntti Palosaari 	}
194fc851c66SAntti Palosaari 
195fc851c66SAntti Palosaari 	if (fe->callback) {
196fc851c66SAntti Palosaari 		ret = fe->callback(client->adapter,
197fc851c66SAntti Palosaari 				   DVB_FRONTEND_COMPONENT_TUNER,
198fc851c66SAntti Palosaari 				   TUA9001_CMD_CEN, 1);
199fc851c66SAntti Palosaari 		if (ret)
200fc851c66SAntti Palosaari 			goto err_kfree;
201fc851c66SAntti Palosaari 
202fc851c66SAntti Palosaari 		ret = fe->callback(client->adapter,
203fc851c66SAntti Palosaari 				   DVB_FRONTEND_COMPONENT_TUNER,
204fc851c66SAntti Palosaari 				   TUA9001_CMD_RXEN, 0);
205fc851c66SAntti Palosaari 		if (ret)
206fc851c66SAntti Palosaari 			goto err_kfree;
207fc851c66SAntti Palosaari 
208fc851c66SAntti Palosaari 		ret = fe->callback(client->adapter,
209fc851c66SAntti Palosaari 				   DVB_FRONTEND_COMPONENT_TUNER,
210fc851c66SAntti Palosaari 				   TUA9001_CMD_RESETN, 1);
211fc851c66SAntti Palosaari 		if (ret)
212fc851c66SAntti Palosaari 			goto err_kfree;
213fc851c66SAntti Palosaari 	}
214fc851c66SAntti Palosaari 
215fc851c66SAntti Palosaari 	fe->tuner_priv = dev;
216fc851c66SAntti Palosaari 	memcpy(&fe->ops.tuner_ops, &tua9001_tuner_ops,
217fc851c66SAntti Palosaari 			sizeof(struct dvb_tuner_ops));
218fc851c66SAntti Palosaari 	i2c_set_clientdata(client, dev);
219fc851c66SAntti Palosaari 
220fc851c66SAntti Palosaari 	dev_info(&client->dev, "Infineon TUA9001 successfully attached\n");
221fc851c66SAntti Palosaari 	return 0;
222fc851c66SAntti Palosaari err_kfree:
223fc851c66SAntti Palosaari 	kfree(dev);
224fc851c66SAntti Palosaari err:
225fc851c66SAntti Palosaari 	dev_dbg(&client->dev, "failed=%d\n", ret);
226fc851c66SAntti Palosaari 	return ret;
227fc851c66SAntti Palosaari }
228fc851c66SAntti Palosaari 
tua9001_remove(struct i2c_client * client)229ed5c2f5fSUwe Kleine-König static void tua9001_remove(struct i2c_client *client)
230fc851c66SAntti Palosaari {
231465433faSAntti Palosaari 	struct tua9001_dev *dev = i2c_get_clientdata(client);
232fc851c66SAntti Palosaari 	struct dvb_frontend *fe = dev->fe;
233fc851c66SAntti Palosaari 	int ret;
234fc851c66SAntti Palosaari 
235fc851c66SAntti Palosaari 	dev_dbg(&client->dev, "\n");
236fc851c66SAntti Palosaari 
237fc851c66SAntti Palosaari 	if (fe->callback) {
238fc851c66SAntti Palosaari 		ret = fe->callback(client->adapter,
239fc851c66SAntti Palosaari 				   DVB_FRONTEND_COMPONENT_TUNER,
240fc851c66SAntti Palosaari 				   TUA9001_CMD_CEN, 0);
241fc851c66SAntti Palosaari 		if (ret)
24248f45c2aSUwe Kleine-König 			dev_err(&client->dev, "Tuner disable failed (%pe)\n", ERR_PTR(ret));
243fc851c66SAntti Palosaari 	}
244fc851c66SAntti Palosaari 	kfree(dev);
245fc851c66SAntti Palosaari }
246fc851c66SAntti Palosaari 
247fc851c66SAntti Palosaari static const struct i2c_device_id tua9001_id_table[] = {
248fc851c66SAntti Palosaari 	{"tua9001", 0},
249fc851c66SAntti Palosaari 	{}
250fc851c66SAntti Palosaari };
251fc851c66SAntti Palosaari MODULE_DEVICE_TABLE(i2c, tua9001_id_table);
252fc851c66SAntti Palosaari 
253fc851c66SAntti Palosaari static struct i2c_driver tua9001_driver = {
254fc851c66SAntti Palosaari 	.driver = {
255fc851c66SAntti Palosaari 		.name	= "tua9001",
256fc851c66SAntti Palosaari 		.suppress_bind_attrs = true,
257fc851c66SAntti Palosaari 	},
258*aaeb31c0SUwe Kleine-König 	.probe		= tua9001_probe,
259fc851c66SAntti Palosaari 	.remove		= tua9001_remove,
260fc851c66SAntti Palosaari 	.id_table	= tua9001_id_table,
261fc851c66SAntti Palosaari };
262fc851c66SAntti Palosaari 
263fc851c66SAntti Palosaari module_i2c_driver(tua9001_driver);
264fc851c66SAntti Palosaari 
265ccae7af2SMauro Carvalho Chehab MODULE_DESCRIPTION("Infineon TUA9001 silicon tuner driver");
266ccae7af2SMauro Carvalho Chehab MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
267ccae7af2SMauro Carvalho Chehab MODULE_LICENSE("GPL");
268