xref: /linux/drivers/media/tuners/tua9001.c (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
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 
tua9001_init(struct dvb_frontend * fe)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 
tua9001_sleep(struct dvb_frontend * fe)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 
tua9001_set_params(struct dvb_frontend * fe)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 
tua9001_get_if_frequency(struct dvb_frontend * fe,u32 * frequency)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 
tua9001_probe(struct i2c_client * client)170 static int tua9001_probe(struct i2c_client *client)
171 {
172 	struct tua9001_dev *dev;
173 	struct tua9001_platform_data *pdata = client->dev.platform_data;
174 	struct dvb_frontend *fe = pdata->dvb_frontend;
175 	int ret;
176 	static const struct regmap_config regmap_config = {
177 		.reg_bits =  8,
178 		.val_bits = 16,
179 	};
180 
181 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
182 	if (!dev) {
183 		ret = -ENOMEM;
184 		goto err;
185 	}
186 
187 	dev->fe = pdata->dvb_frontend;
188 	dev->client = client;
189 	dev->regmap = devm_regmap_init_i2c(client, &regmap_config);
190 	if (IS_ERR(dev->regmap)) {
191 		ret = PTR_ERR(dev->regmap);
192 		goto err_kfree;
193 	}
194 
195 	if (fe->callback) {
196 		ret = fe->callback(client->adapter,
197 				   DVB_FRONTEND_COMPONENT_TUNER,
198 				   TUA9001_CMD_CEN, 1);
199 		if (ret)
200 			goto err_kfree;
201 
202 		ret = fe->callback(client->adapter,
203 				   DVB_FRONTEND_COMPONENT_TUNER,
204 				   TUA9001_CMD_RXEN, 0);
205 		if (ret)
206 			goto err_kfree;
207 
208 		ret = fe->callback(client->adapter,
209 				   DVB_FRONTEND_COMPONENT_TUNER,
210 				   TUA9001_CMD_RESETN, 1);
211 		if (ret)
212 			goto err_kfree;
213 	}
214 
215 	fe->tuner_priv = dev;
216 	memcpy(&fe->ops.tuner_ops, &tua9001_tuner_ops,
217 			sizeof(struct dvb_tuner_ops));
218 	i2c_set_clientdata(client, dev);
219 
220 	dev_info(&client->dev, "Infineon TUA9001 successfully attached\n");
221 	return 0;
222 err_kfree:
223 	kfree(dev);
224 err:
225 	dev_dbg(&client->dev, "failed=%d\n", ret);
226 	return ret;
227 }
228 
tua9001_remove(struct i2c_client * client)229 static void tua9001_remove(struct i2c_client *client)
230 {
231 	struct tua9001_dev *dev = i2c_get_clientdata(client);
232 	struct dvb_frontend *fe = dev->fe;
233 	int ret;
234 
235 	dev_dbg(&client->dev, "\n");
236 
237 	if (fe->callback) {
238 		ret = fe->callback(client->adapter,
239 				   DVB_FRONTEND_COMPONENT_TUNER,
240 				   TUA9001_CMD_CEN, 0);
241 		if (ret)
242 			dev_err(&client->dev, "Tuner disable failed (%pe)\n", ERR_PTR(ret));
243 	}
244 	kfree(dev);
245 }
246 
247 static const struct i2c_device_id tua9001_id_table[] = {
248 	{ "tua9001" },
249 	{}
250 };
251 MODULE_DEVICE_TABLE(i2c, tua9001_id_table);
252 
253 static struct i2c_driver tua9001_driver = {
254 	.driver = {
255 		.name	= "tua9001",
256 		.suppress_bind_attrs = true,
257 	},
258 	.probe		= tua9001_probe,
259 	.remove		= tua9001_remove,
260 	.id_table	= tua9001_id_table,
261 };
262 
263 module_i2c_driver(tua9001_driver);
264 
265 MODULE_DESCRIPTION("Infineon TUA9001 silicon tuner driver");
266 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
267 MODULE_LICENSE("GPL");
268