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