0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013 #include <linux/errno.h>
0014 #include <linux/i2c.h>
0015 #include <linux/module.h>
0016 #include <linux/printk.h>
0017 #include <linux/ratelimit.h>
0018 #include <linux/slab.h>
0019 #include <linux/types.h>
0020
0021 #include <media/dvb_frontend.h>
0022
0023 #include "vidtv_tuner.h"
0024
0025 struct vidtv_tuner_cnr_to_qual_s {
0026
0027 u32 modulation;
0028 u32 fec;
0029 u32 cnr_ok;
0030 u32 cnr_good;
0031 };
0032
0033 static const struct vidtv_tuner_cnr_to_qual_s vidtv_tuner_c_cnr_2_qual[] = {
0034
0035 { QAM_256, FEC_NONE, 34000, 38000},
0036 { QAM_64, FEC_NONE, 30000, 34000},
0037 };
0038
0039 static const struct vidtv_tuner_cnr_to_qual_s vidtv_tuner_s_cnr_2_qual[] = {
0040
0041 { QPSK, FEC_1_2, 7000, 10000},
0042 { QPSK, FEC_2_3, 9000, 12000},
0043 { QPSK, FEC_3_4, 10000, 13000},
0044 { QPSK, FEC_5_6, 11000, 14000},
0045 { QPSK, FEC_7_8, 12000, 15000},
0046 };
0047
0048 static const struct vidtv_tuner_cnr_to_qual_s vidtv_tuner_s2_cnr_2_qual[] = {
0049
0050 { QPSK, FEC_1_2, 9000, 12000},
0051 { QPSK, FEC_2_3, 11000, 14000},
0052 { QPSK, FEC_3_4, 12000, 15000},
0053 { QPSK, FEC_5_6, 12000, 15000},
0054 { QPSK, FEC_8_9, 13000, 16000},
0055 { QPSK, FEC_9_10, 13500, 16500},
0056 { PSK_8, FEC_2_3, 14500, 17500},
0057 { PSK_8, FEC_3_4, 16000, 19000},
0058 { PSK_8, FEC_5_6, 17500, 20500},
0059 { PSK_8, FEC_8_9, 19000, 22000},
0060 };
0061
0062 static const struct vidtv_tuner_cnr_to_qual_s vidtv_tuner_t_cnr_2_qual[] = {
0063
0064 { QPSK, FEC_1_2, 4100, 5900},
0065 { QPSK, FEC_2_3, 6100, 9600},
0066 { QPSK, FEC_3_4, 7200, 12400},
0067 { QPSK, FEC_5_6, 8500, 15600},
0068 { QPSK, FEC_7_8, 9200, 17500},
0069 { QAM_16, FEC_1_2, 9800, 11800},
0070 { QAM_16, FEC_2_3, 12100, 15300},
0071 { QAM_16, FEC_3_4, 13400, 18100},
0072 { QAM_16, FEC_5_6, 14800, 21300},
0073 { QAM_16, FEC_7_8, 15700, 23600},
0074 { QAM_64, FEC_1_2, 14000, 16000},
0075 { QAM_64, FEC_2_3, 19900, 25400},
0076 { QAM_64, FEC_3_4, 24900, 27900},
0077 { QAM_64, FEC_5_6, 21300, 23300},
0078 { QAM_64, FEC_7_8, 22000, 24000},
0079 };
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095 struct vidtv_tuner_hardware_state {
0096 bool asleep;
0097 u32 lock_status;
0098 u32 if_frequency;
0099 u32 tuned_frequency;
0100 u32 bandwidth;
0101 };
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112 struct vidtv_tuner_dev {
0113 struct dvb_frontend *fe;
0114 struct vidtv_tuner_hardware_state hw_state;
0115 struct vidtv_tuner_config config;
0116 };
0117
0118 static struct vidtv_tuner_dev*
0119 vidtv_tuner_get_dev(struct dvb_frontend *fe)
0120 {
0121 return i2c_get_clientdata(fe->tuner_priv);
0122 }
0123
0124 static int vidtv_tuner_check_frequency_shift(struct dvb_frontend *fe)
0125 {
0126 struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
0127 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
0128 struct vidtv_tuner_config config = tuner_dev->config;
0129 u32 *valid_freqs = NULL;
0130 u32 array_sz = 0;
0131 u32 i;
0132 u32 shift;
0133
0134 switch (c->delivery_system) {
0135 case SYS_DVBT:
0136 case SYS_DVBT2:
0137 valid_freqs = config.vidtv_valid_dvb_t_freqs;
0138 array_sz = ARRAY_SIZE(config.vidtv_valid_dvb_t_freqs);
0139 break;
0140 case SYS_DVBS:
0141 case SYS_DVBS2:
0142 valid_freqs = config.vidtv_valid_dvb_s_freqs;
0143 array_sz = ARRAY_SIZE(config.vidtv_valid_dvb_s_freqs);
0144 break;
0145 case SYS_DVBC_ANNEX_A:
0146 valid_freqs = config.vidtv_valid_dvb_c_freqs;
0147 array_sz = ARRAY_SIZE(config.vidtv_valid_dvb_c_freqs);
0148 break;
0149
0150 default:
0151 dev_warn(fe->dvb->device,
0152 "%s: unsupported delivery system: %u\n",
0153 __func__,
0154 c->delivery_system);
0155
0156 return -EINVAL;
0157 }
0158
0159 for (i = 0; i < array_sz; i++) {
0160 if (!valid_freqs[i])
0161 break;
0162 shift = abs(c->frequency - valid_freqs[i]);
0163
0164 if (!shift)
0165 return 0;
0166
0167
0168
0169
0170
0171
0172 if (shift < config.max_frequency_shift_hz)
0173 return shift * 100 / config.max_frequency_shift_hz;
0174 }
0175
0176 return -EINVAL;
0177 }
0178
0179 static int
0180 vidtv_tuner_get_signal_strength(struct dvb_frontend *fe, u16 *strength)
0181 {
0182 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
0183 struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
0184 const struct vidtv_tuner_cnr_to_qual_s *cnr2qual = NULL;
0185 struct device *dev = fe->dvb->device;
0186 u32 array_size = 0;
0187 s32 shift;
0188 u32 i;
0189
0190 shift = vidtv_tuner_check_frequency_shift(fe);
0191 if (shift < 0) {
0192 tuner_dev->hw_state.lock_status = 0;
0193 *strength = 0;
0194 return 0;
0195 }
0196
0197 switch (c->delivery_system) {
0198 case SYS_DVBT:
0199 case SYS_DVBT2:
0200 cnr2qual = vidtv_tuner_t_cnr_2_qual;
0201 array_size = ARRAY_SIZE(vidtv_tuner_t_cnr_2_qual);
0202 break;
0203
0204 case SYS_DVBS:
0205 cnr2qual = vidtv_tuner_s_cnr_2_qual;
0206 array_size = ARRAY_SIZE(vidtv_tuner_s_cnr_2_qual);
0207 break;
0208
0209 case SYS_DVBS2:
0210 cnr2qual = vidtv_tuner_s2_cnr_2_qual;
0211 array_size = ARRAY_SIZE(vidtv_tuner_s2_cnr_2_qual);
0212 break;
0213
0214 case SYS_DVBC_ANNEX_A:
0215 cnr2qual = vidtv_tuner_c_cnr_2_qual;
0216 array_size = ARRAY_SIZE(vidtv_tuner_c_cnr_2_qual);
0217 break;
0218
0219 default:
0220 dev_warn_ratelimited(dev,
0221 "%s: unsupported delivery system: %u\n",
0222 __func__,
0223 c->delivery_system);
0224 return -EINVAL;
0225 }
0226
0227 for (i = 0; i < array_size; i++) {
0228 if (cnr2qual[i].modulation != c->modulation ||
0229 cnr2qual[i].fec != c->fec_inner)
0230 continue;
0231
0232 if (!shift) {
0233 *strength = cnr2qual[i].cnr_good;
0234 return 0;
0235 }
0236
0237
0238
0239
0240
0241 *strength = cnr2qual[i].cnr_ok -
0242 (cnr2qual[i].cnr_good - cnr2qual[i].cnr_ok);
0243 return 0;
0244 }
0245
0246
0247
0248
0249
0250 *strength = 34000 - 24000 * shift / 100;
0251 return 0;
0252 }
0253
0254 static int vidtv_tuner_init(struct dvb_frontend *fe)
0255 {
0256 struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
0257 struct vidtv_tuner_config config = tuner_dev->config;
0258
0259 msleep_interruptible(config.mock_power_up_delay_msec);
0260
0261 tuner_dev->hw_state.asleep = false;
0262 tuner_dev->hw_state.if_frequency = 5000;
0263
0264 return 0;
0265 }
0266
0267 static int vidtv_tuner_sleep(struct dvb_frontend *fe)
0268 {
0269 struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
0270
0271 tuner_dev->hw_state.asleep = true;
0272 return 0;
0273 }
0274
0275 static int vidtv_tuner_suspend(struct dvb_frontend *fe)
0276 {
0277 struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
0278
0279 tuner_dev->hw_state.asleep = true;
0280 return 0;
0281 }
0282
0283 static int vidtv_tuner_resume(struct dvb_frontend *fe)
0284 {
0285 struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
0286
0287 tuner_dev->hw_state.asleep = false;
0288 return 0;
0289 }
0290
0291 static int vidtv_tuner_set_params(struct dvb_frontend *fe)
0292 {
0293 struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
0294 struct vidtv_tuner_config config = tuner_dev->config;
0295 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
0296 s32 shift;
0297
0298 u32 min_freq = fe->ops.tuner_ops.info.frequency_min_hz;
0299 u32 max_freq = fe->ops.tuner_ops.info.frequency_max_hz;
0300 u32 min_bw = fe->ops.tuner_ops.info.bandwidth_min;
0301 u32 max_bw = fe->ops.tuner_ops.info.bandwidth_max;
0302
0303 if (c->frequency < min_freq || c->frequency > max_freq ||
0304 c->bandwidth_hz < min_bw || c->bandwidth_hz > max_bw) {
0305 tuner_dev->hw_state.lock_status = 0;
0306 return -EINVAL;
0307 }
0308
0309 tuner_dev->hw_state.tuned_frequency = c->frequency;
0310 tuner_dev->hw_state.bandwidth = c->bandwidth_hz;
0311 tuner_dev->hw_state.lock_status = TUNER_STATUS_LOCKED;
0312
0313 msleep_interruptible(config.mock_tune_delay_msec);
0314
0315 shift = vidtv_tuner_check_frequency_shift(fe);
0316 if (shift < 0) {
0317 tuner_dev->hw_state.lock_status = 0;
0318 return shift;
0319 }
0320
0321 return 0;
0322 }
0323
0324 static int vidtv_tuner_set_config(struct dvb_frontend *fe,
0325 void *priv_cfg)
0326 {
0327 struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
0328
0329 memcpy(&tuner_dev->config, priv_cfg, sizeof(tuner_dev->config));
0330
0331 return 0;
0332 }
0333
0334 static int vidtv_tuner_get_frequency(struct dvb_frontend *fe,
0335 u32 *frequency)
0336 {
0337 struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
0338
0339 *frequency = tuner_dev->hw_state.tuned_frequency;
0340
0341 return 0;
0342 }
0343
0344 static int vidtv_tuner_get_bandwidth(struct dvb_frontend *fe,
0345 u32 *bandwidth)
0346 {
0347 struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
0348
0349 *bandwidth = tuner_dev->hw_state.bandwidth;
0350
0351 return 0;
0352 }
0353
0354 static int vidtv_tuner_get_if_frequency(struct dvb_frontend *fe,
0355 u32 *frequency)
0356 {
0357 struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
0358
0359 *frequency = tuner_dev->hw_state.if_frequency;
0360
0361 return 0;
0362 }
0363
0364 static int vidtv_tuner_get_status(struct dvb_frontend *fe, u32 *status)
0365 {
0366 struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
0367
0368 *status = tuner_dev->hw_state.lock_status;
0369
0370 return 0;
0371 }
0372
0373 static const struct dvb_tuner_ops vidtv_tuner_ops = {
0374 .init = vidtv_tuner_init,
0375 .sleep = vidtv_tuner_sleep,
0376 .suspend = vidtv_tuner_suspend,
0377 .resume = vidtv_tuner_resume,
0378 .set_params = vidtv_tuner_set_params,
0379 .set_config = vidtv_tuner_set_config,
0380 .get_bandwidth = vidtv_tuner_get_bandwidth,
0381 .get_frequency = vidtv_tuner_get_frequency,
0382 .get_if_frequency = vidtv_tuner_get_if_frequency,
0383 .get_status = vidtv_tuner_get_status,
0384 .get_rf_strength = vidtv_tuner_get_signal_strength
0385 };
0386
0387 static const struct i2c_device_id vidtv_tuner_i2c_id_table[] = {
0388 {"dvb_vidtv_tuner", 0},
0389 {}
0390 };
0391 MODULE_DEVICE_TABLE(i2c, vidtv_tuner_i2c_id_table);
0392
0393 static int vidtv_tuner_i2c_probe(struct i2c_client *client,
0394 const struct i2c_device_id *id)
0395 {
0396 struct vidtv_tuner_config *config = client->dev.platform_data;
0397 struct dvb_frontend *fe = config->fe;
0398 struct vidtv_tuner_dev *tuner_dev = NULL;
0399
0400 tuner_dev = kzalloc(sizeof(*tuner_dev), GFP_KERNEL);
0401 if (!tuner_dev)
0402 return -ENOMEM;
0403
0404 tuner_dev->fe = config->fe;
0405 i2c_set_clientdata(client, tuner_dev);
0406
0407 memcpy(&fe->ops.tuner_ops,
0408 &vidtv_tuner_ops,
0409 sizeof(struct dvb_tuner_ops));
0410
0411 memcpy(&tuner_dev->config, config, sizeof(tuner_dev->config));
0412 fe->tuner_priv = client;
0413
0414 return 0;
0415 }
0416
0417 static int vidtv_tuner_i2c_remove(struct i2c_client *client)
0418 {
0419 struct vidtv_tuner_dev *tuner_dev = i2c_get_clientdata(client);
0420
0421 kfree(tuner_dev);
0422
0423 return 0;
0424 }
0425
0426 static struct i2c_driver vidtv_tuner_i2c_driver = {
0427 .driver = {
0428 .name = "dvb_vidtv_tuner",
0429 .suppress_bind_attrs = true,
0430 },
0431 .probe = vidtv_tuner_i2c_probe,
0432 .remove = vidtv_tuner_i2c_remove,
0433 .id_table = vidtv_tuner_i2c_id_table,
0434 };
0435 module_i2c_driver(vidtv_tuner_i2c_driver);
0436
0437 MODULE_DESCRIPTION("Virtual DVB Tuner");
0438 MODULE_AUTHOR("Daniel W. S. Almeida");
0439 MODULE_LICENSE("GPL");