xref: /openbmc/linux/drivers/media/tuners/tda18212.c (revision 60772e48)
1 /*
2  * NXP TDA18212HN silicon tuner driver
3  *
4  * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
5  *
6  *    This program is free software; you can redistribute it and/or modify
7  *    it under the terms of the GNU General Public License as published by
8  *    the Free Software Foundation; either version 2 of the License, or
9  *    (at your option) any later version.
10  *
11  *    This program is distributed in the hope that it will be useful,
12  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *    GNU General Public License for more details.
15  *
16  *    You should have received a copy of the GNU General Public License along
17  *    with this program; if not, write to the Free Software Foundation, Inc.,
18  *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20 
21 #include "tda18212.h"
22 #include <linux/regmap.h>
23 
24 struct tda18212_dev {
25 	struct tda18212_config cfg;
26 	struct i2c_client *client;
27 	struct regmap *regmap;
28 
29 	u32 if_frequency;
30 };
31 
32 static int tda18212_set_params(struct dvb_frontend *fe)
33 {
34 	struct tda18212_dev *dev = fe->tuner_priv;
35 	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
36 	int ret, i;
37 	u32 if_khz;
38 	u8 buf[9];
39 	#define DVBT_6   0
40 	#define DVBT_7   1
41 	#define DVBT_8   2
42 	#define DVBT2_6  3
43 	#define DVBT2_7  4
44 	#define DVBT2_8  5
45 	#define DVBC_6   6
46 	#define DVBC_8   7
47 	#define ATSC_VSB 8
48 	#define ATSC_QAM 9
49 	static const u8 bw_params[][3] = {
50 		     /* reg:   0f    13    23 */
51 		[DVBT_6]  = { 0xb3, 0x20, 0x03 },
52 		[DVBT_7]  = { 0xb3, 0x31, 0x01 },
53 		[DVBT_8]  = { 0xb3, 0x22, 0x01 },
54 		[DVBT2_6] = { 0xbc, 0x20, 0x03 },
55 		[DVBT2_7] = { 0xbc, 0x72, 0x03 },
56 		[DVBT2_8] = { 0xbc, 0x22, 0x01 },
57 		[DVBC_6]  = { 0x92, 0x50, 0x03 },
58 		[DVBC_8]  = { 0x92, 0x53, 0x03 },
59 		[ATSC_VSB] = { 0x7d, 0x20, 0x63 },
60 		[ATSC_QAM] = { 0x7d, 0x20, 0x63 },
61 	};
62 
63 	dev_dbg(&dev->client->dev,
64 			"delivery_system=%d frequency=%d bandwidth_hz=%d\n",
65 			c->delivery_system, c->frequency,
66 			c->bandwidth_hz);
67 
68 	if (fe->ops.i2c_gate_ctrl)
69 		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
70 
71 	switch (c->delivery_system) {
72 	case SYS_ATSC:
73 		if_khz = dev->cfg.if_atsc_vsb;
74 		i = ATSC_VSB;
75 		break;
76 	case SYS_DVBC_ANNEX_B:
77 		if_khz = dev->cfg.if_atsc_qam;
78 		i = ATSC_QAM;
79 		break;
80 	case SYS_DVBT:
81 		switch (c->bandwidth_hz) {
82 		case 6000000:
83 			if_khz = dev->cfg.if_dvbt_6;
84 			i = DVBT_6;
85 			break;
86 		case 7000000:
87 			if_khz = dev->cfg.if_dvbt_7;
88 			i = DVBT_7;
89 			break;
90 		case 8000000:
91 			if_khz = dev->cfg.if_dvbt_8;
92 			i = DVBT_8;
93 			break;
94 		default:
95 			ret = -EINVAL;
96 			goto error;
97 		}
98 		break;
99 	case SYS_DVBT2:
100 		switch (c->bandwidth_hz) {
101 		case 6000000:
102 			if_khz = dev->cfg.if_dvbt2_6;
103 			i = DVBT2_6;
104 			break;
105 		case 7000000:
106 			if_khz = dev->cfg.if_dvbt2_7;
107 			i = DVBT2_7;
108 			break;
109 		case 8000000:
110 			if_khz = dev->cfg.if_dvbt2_8;
111 			i = DVBT2_8;
112 			break;
113 		default:
114 			ret = -EINVAL;
115 			goto error;
116 		}
117 		break;
118 	case SYS_DVBC_ANNEX_A:
119 	case SYS_DVBC_ANNEX_C:
120 		if_khz = dev->cfg.if_dvbc;
121 		i = DVBC_8;
122 		break;
123 	default:
124 		ret = -EINVAL;
125 		goto error;
126 	}
127 
128 	ret = regmap_write(dev->regmap, 0x23, bw_params[i][2]);
129 	if (ret)
130 		goto error;
131 
132 	ret = regmap_write(dev->regmap, 0x06, 0x00);
133 	if (ret)
134 		goto error;
135 
136 	ret = regmap_write(dev->regmap, 0x0f, bw_params[i][0]);
137 	if (ret)
138 		goto error;
139 
140 	buf[0] = 0x02;
141 	buf[1] = bw_params[i][1];
142 	buf[2] = 0x03; /* default value */
143 	buf[3] = DIV_ROUND_CLOSEST(if_khz, 50);
144 	buf[4] = ((c->frequency / 1000) >> 16) & 0xff;
145 	buf[5] = ((c->frequency / 1000) >>  8) & 0xff;
146 	buf[6] = ((c->frequency / 1000) >>  0) & 0xff;
147 	buf[7] = 0xc1;
148 	buf[8] = 0x01;
149 	ret = regmap_bulk_write(dev->regmap, 0x12, buf, sizeof(buf));
150 	if (ret)
151 		goto error;
152 
153 	/* actual IF rounded as it is on register */
154 	dev->if_frequency = buf[3] * 50 * 1000;
155 
156 exit:
157 	if (fe->ops.i2c_gate_ctrl)
158 		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
159 
160 	return ret;
161 
162 error:
163 	dev_dbg(&dev->client->dev, "failed=%d\n", ret);
164 	goto exit;
165 }
166 
167 static int tda18212_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
168 {
169 	struct tda18212_dev *dev = fe->tuner_priv;
170 
171 	*frequency = dev->if_frequency;
172 
173 	return 0;
174 }
175 
176 static const struct dvb_tuner_ops tda18212_tuner_ops = {
177 	.info = {
178 		.name           = "NXP TDA18212",
179 
180 		.frequency_min  =  48000000,
181 		.frequency_max  = 864000000,
182 		.frequency_step =      1000,
183 	},
184 
185 	.set_params    = tda18212_set_params,
186 	.get_if_frequency = tda18212_get_if_frequency,
187 };
188 
189 static int tda18212_probe(struct i2c_client *client,
190 		const struct i2c_device_id *id)
191 {
192 	struct tda18212_config *cfg = client->dev.platform_data;
193 	struct dvb_frontend *fe = cfg->fe;
194 	struct tda18212_dev *dev;
195 	int ret;
196 	unsigned int chip_id;
197 	char *version;
198 	static const struct regmap_config regmap_config = {
199 		.reg_bits = 8,
200 		.val_bits = 8,
201 	};
202 
203 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
204 	if (dev == NULL) {
205 		ret = -ENOMEM;
206 		dev_err(&client->dev, "kzalloc() failed\n");
207 		goto err;
208 	}
209 
210 	memcpy(&dev->cfg, cfg, sizeof(struct tda18212_config));
211 	dev->client = client;
212 	dev->regmap = devm_regmap_init_i2c(client, &regmap_config);
213 	if (IS_ERR(dev->regmap)) {
214 		ret = PTR_ERR(dev->regmap);
215 		goto err;
216 	}
217 
218 	/* check if the tuner is there */
219 	if (fe->ops.i2c_gate_ctrl)
220 		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
221 
222 	ret = regmap_read(dev->regmap, 0x00, &chip_id);
223 	dev_dbg(&dev->client->dev, "chip_id=%02x\n", chip_id);
224 
225 	if (fe->ops.i2c_gate_ctrl)
226 		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
227 
228 	if (ret)
229 		goto err;
230 
231 	switch (chip_id) {
232 	case 0xc7:
233 		version = "M"; /* master */
234 		break;
235 	case 0x47:
236 		version = "S"; /* slave */
237 		break;
238 	default:
239 		ret = -ENODEV;
240 		goto err;
241 	}
242 
243 	dev_info(&dev->client->dev,
244 			"NXP TDA18212HN/%s successfully identified\n", version);
245 
246 	fe->tuner_priv = dev;
247 	memcpy(&fe->ops.tuner_ops, &tda18212_tuner_ops,
248 			sizeof(struct dvb_tuner_ops));
249 	i2c_set_clientdata(client, dev);
250 
251 	return 0;
252 err:
253 	dev_dbg(&client->dev, "failed=%d\n", ret);
254 	kfree(dev);
255 	return ret;
256 }
257 
258 static int tda18212_remove(struct i2c_client *client)
259 {
260 	struct tda18212_dev *dev = i2c_get_clientdata(client);
261 	struct dvb_frontend *fe = dev->cfg.fe;
262 
263 	dev_dbg(&client->dev, "\n");
264 
265 	memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
266 	fe->tuner_priv = NULL;
267 	kfree(dev);
268 
269 	return 0;
270 }
271 
272 static const struct i2c_device_id tda18212_id[] = {
273 	{"tda18212", 0},
274 	{}
275 };
276 MODULE_DEVICE_TABLE(i2c, tda18212_id);
277 
278 static struct i2c_driver tda18212_driver = {
279 	.driver = {
280 		.name	= "tda18212",
281 	},
282 	.probe		= tda18212_probe,
283 	.remove		= tda18212_remove,
284 	.id_table	= tda18212_id,
285 };
286 
287 module_i2c_driver(tda18212_driver);
288 
289 MODULE_DESCRIPTION("NXP TDA18212HN silicon tuner driver");
290 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
291 MODULE_LICENSE("GPL");
292