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