Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Sharp QM1D1B0004 satellite tuner
0004  *
0005  * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com>
0006  *
0007  * based on (former) drivers/media/pci/pt1/va1j5jf8007s.c.
0008  */
0009 
0010 /*
0011  * Note:
0012  * Since the data-sheet of this tuner chip is not available,
0013  * this driver lacks some tuner_ops and config options.
0014  * In addition, the implementation might be dependent on the specific use
0015  * in the FE module: VA1J5JF8007S and/or in the product: Earthsoft PT1/PT2.
0016  */
0017 
0018 #include <linux/kernel.h>
0019 #include <linux/module.h>
0020 #include <media/dvb_frontend.h>
0021 #include "qm1d1b0004.h"
0022 
0023 /*
0024  * Tuner I/F (copied from the former va1j5jf8007s.c)
0025  * b[0] I2C addr
0026  * b[1] "0":1, BG:2, divider_quotient[7:3]:5
0027  * b[2] divider_quotient[2:0]:3, divider_remainder:5
0028  * b[3] "111":3, LPF[3:2]:2, TM:1, "0":1, REF:1
0029  * b[4] BANDX, PSC:1, LPF[1:0]:2, DIV:1, "0":1
0030  *
0031  * PLL frequency step :=
0032  *    REF == 0 -> PLL XTL frequency(4MHz) / 8
0033  *    REF == 1 -> PLL XTL frequency(4MHz) / 4
0034  *
0035  * PreScaler :=
0036  *    PSC == 0 -> x32
0037  *    PSC == 1 -> x16
0038  *
0039  * divider_quotient := (frequency / PLL frequency step) / PreScaler
0040  * divider_remainder := (frequency / PLL frequency step) % PreScaler
0041  *
0042  * LPF := LPF Frequency / 1000 / 2 - 2
0043  * LPF Frequency @ baudrate=28.86Mbps = 30000
0044  *
0045  * band (1..9)
0046  *   band 1 (freq <  986000) -> DIV:1, BANDX:5, PSC:1
0047  *   band 2 (freq < 1072000) -> DIV:1, BANDX:6, PSC:1
0048  *   band 3 (freq < 1154000) -> DIV:1, BANDX:7, PSC:0
0049  *   band 4 (freq < 1291000) -> DIV:0, BANDX:1, PSC:0
0050  *   band 5 (freq < 1447000) -> DIV:0, BANDX:2, PSC:0
0051  *   band 6 (freq < 1615000) -> DIV:0, BANDX:3, PSC:0
0052  *   band 7 (freq < 1791000) -> DIV:0, BANDX:4, PSC:0
0053  *   band 8 (freq < 1972000) -> DIV:0, BANDX:5, PSC:0
0054  *   band 9 (freq < 2150000) -> DIV:0, BANDX:6, PSC:0
0055  */
0056 
0057 #define QM1D1B0004_PSC_MASK (1 << 4)
0058 
0059 #define QM1D1B0004_XTL_FREQ 4000
0060 #define QM1D1B0004_LPF_FALLBACK 30000
0061 
0062 #if 0 /* Currently unused */
0063 static const struct qm1d1b0004_config default_cfg = {
0064     .lpf_freq = QM1D1B0004_CFG_LPF_DFLT,
0065     .half_step = false,
0066 };
0067 #endif
0068 
0069 struct qm1d1b0004_state {
0070     struct qm1d1b0004_config cfg;
0071     struct i2c_client *i2c;
0072 };
0073 
0074 
0075 struct qm1d1b0004_cb_map {
0076     u32 frequency;
0077     u8 cb;
0078 };
0079 
0080 static const struct qm1d1b0004_cb_map cb_maps[] = {
0081     {  986000, 0xb2 },
0082     { 1072000, 0xd2 },
0083     { 1154000, 0xe2 },
0084     { 1291000, 0x20 },
0085     { 1447000, 0x40 },
0086     { 1615000, 0x60 },
0087     { 1791000, 0x80 },
0088     { 1972000, 0xa0 },
0089 };
0090 
0091 static u8 lookup_cb(u32 frequency)
0092 {
0093     int i;
0094     const struct qm1d1b0004_cb_map *map;
0095 
0096     for (i = 0; i < ARRAY_SIZE(cb_maps); i++) {
0097         map = &cb_maps[i];
0098         if (frequency < map->frequency)
0099             return map->cb;
0100     }
0101     return 0xc0;
0102 }
0103 
0104 static int qm1d1b0004_set_params(struct dvb_frontend *fe)
0105 {
0106     struct qm1d1b0004_state *state;
0107     u32 frequency, pll, lpf_freq;
0108     u16 word;
0109     u8 buf[4], cb, lpf;
0110     int ret;
0111 
0112     state = fe->tuner_priv;
0113     frequency = fe->dtv_property_cache.frequency;
0114 
0115     pll = QM1D1B0004_XTL_FREQ / 4;
0116     if (state->cfg.half_step)
0117         pll /= 2;
0118     word = DIV_ROUND_CLOSEST(frequency, pll);
0119     cb = lookup_cb(frequency);
0120     if (cb & QM1D1B0004_PSC_MASK)
0121         word = (word << 1 & ~0x1f) | (word & 0x0f);
0122 
0123     /* step.1: set frequency with BG:2, TM:0(4MHZ), LPF:4MHz */
0124     buf[0] = 0x40 | word >> 8;
0125     buf[1] = word;
0126     /* inconsisnten with the above I/F doc. maybe the doc is wrong */
0127     buf[2] = 0xe0 | state->cfg.half_step;
0128     buf[3] = cb;
0129     ret = i2c_master_send(state->i2c, buf, 4);
0130     if (ret < 0)
0131         return ret;
0132 
0133     /* step.2: set TM:1 */
0134     buf[0] = 0xe4 | state->cfg.half_step;
0135     ret = i2c_master_send(state->i2c, buf, 1);
0136     if (ret < 0)
0137         return ret;
0138     msleep(20);
0139 
0140     /* step.3: set LPF */
0141     lpf_freq = state->cfg.lpf_freq;
0142     if (lpf_freq == QM1D1B0004_CFG_LPF_DFLT)
0143         lpf_freq = fe->dtv_property_cache.symbol_rate / 1000;
0144     if (lpf_freq == 0)
0145         lpf_freq = QM1D1B0004_LPF_FALLBACK;
0146     lpf = DIV_ROUND_UP(lpf_freq, 2000) - 2;
0147     buf[0] = 0xe4 | ((lpf & 0x0c) << 1) | state->cfg.half_step;
0148     buf[1] = cb | ((lpf & 0x03) << 2);
0149     ret = i2c_master_send(state->i2c, buf, 2);
0150     if (ret < 0)
0151         return ret;
0152 
0153     /* step.4: read PLL lock? */
0154     buf[0] = 0;
0155     ret = i2c_master_recv(state->i2c, buf, 1);
0156     if (ret < 0)
0157         return ret;
0158     return 0;
0159 }
0160 
0161 
0162 static int qm1d1b0004_set_config(struct dvb_frontend *fe, void *priv_cfg)
0163 {
0164     struct qm1d1b0004_state *state;
0165 
0166     state = fe->tuner_priv;
0167     memcpy(&state->cfg, priv_cfg, sizeof(state->cfg));
0168     return 0;
0169 }
0170 
0171 
0172 static int qm1d1b0004_init(struct dvb_frontend *fe)
0173 {
0174     struct qm1d1b0004_state *state;
0175     u8 buf[2] = {0xf8, 0x04};
0176 
0177     state = fe->tuner_priv;
0178     if (state->cfg.half_step)
0179         buf[0] |= 0x01;
0180 
0181     return i2c_master_send(state->i2c, buf, 2);
0182 }
0183 
0184 
0185 static const struct dvb_tuner_ops qm1d1b0004_ops = {
0186     .info = {
0187         .name = "Sharp qm1d1b0004",
0188 
0189         .frequency_min_hz =  950 * MHz,
0190         .frequency_max_hz = 2150 * MHz,
0191     },
0192 
0193     .init = qm1d1b0004_init,
0194 
0195     .set_params = qm1d1b0004_set_params,
0196     .set_config = qm1d1b0004_set_config,
0197 };
0198 
0199 static int
0200 qm1d1b0004_probe(struct i2c_client *client, const struct i2c_device_id *id)
0201 {
0202     struct dvb_frontend *fe;
0203     struct qm1d1b0004_config *cfg;
0204     struct qm1d1b0004_state *state;
0205     int ret;
0206 
0207     cfg = client->dev.platform_data;
0208     fe = cfg->fe;
0209     i2c_set_clientdata(client, fe);
0210 
0211     fe->tuner_priv = kzalloc(sizeof(struct qm1d1b0004_state), GFP_KERNEL);
0212     if (!fe->tuner_priv) {
0213         ret = -ENOMEM;
0214         goto err_mem;
0215     }
0216 
0217     memcpy(&fe->ops.tuner_ops, &qm1d1b0004_ops, sizeof(fe->ops.tuner_ops));
0218 
0219     state = fe->tuner_priv;
0220     state->i2c = client;
0221     ret = qm1d1b0004_set_config(fe, cfg);
0222     if (ret != 0)
0223         goto err_priv;
0224 
0225     dev_info(&client->dev, "Sharp QM1D1B0004 attached.\n");
0226     return 0;
0227 
0228 err_priv:
0229     kfree(fe->tuner_priv);
0230 err_mem:
0231     fe->tuner_priv = NULL;
0232     return ret;
0233 }
0234 
0235 static int qm1d1b0004_remove(struct i2c_client *client)
0236 {
0237     struct dvb_frontend *fe;
0238 
0239     fe = i2c_get_clientdata(client);
0240     kfree(fe->tuner_priv);
0241     fe->tuner_priv = NULL;
0242     return 0;
0243 }
0244 
0245 
0246 static const struct i2c_device_id qm1d1b0004_id[] = {
0247     {"qm1d1b0004", 0},
0248     {}
0249 };
0250 
0251 MODULE_DEVICE_TABLE(i2c, qm1d1b0004_id);
0252 
0253 static struct i2c_driver qm1d1b0004_driver = {
0254     .driver = {
0255         .name = "qm1d1b0004",
0256     },
0257     .probe    = qm1d1b0004_probe,
0258     .remove   = qm1d1b0004_remove,
0259     .id_table = qm1d1b0004_id,
0260 };
0261 
0262 module_i2c_driver(qm1d1b0004_driver);
0263 
0264 MODULE_DESCRIPTION("Sharp QM1D1B0004");
0265 MODULE_AUTHOR("Akihiro Tsukada");
0266 MODULE_LICENSE("GPL");