Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Sharp QM1D1C0042 8PSK tuner driver
0004  *
0005  * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com>
0006  */
0007 
0008 /*
0009  * NOTICE:
0010  * As the disclosed information on the chip is very limited,
0011  * this driver lacks some features, including chip config like IF freq.
0012  * It assumes that users of this driver (such as a PCI bridge of
0013  * DTV receiver cards) know the relevant info and
0014  * configure the chip via I2C if necessary.
0015  *
0016  * Currently, PT3 driver is the only one that uses this driver,
0017  * and contains init/config code in its firmware.
0018  * Thus some part of the code might be dependent on PT3 specific config.
0019  */
0020 
0021 #include <linux/kernel.h>
0022 #include <linux/math64.h>
0023 #include "qm1d1c0042.h"
0024 
0025 #define QM1D1C0042_NUM_REGS 0x20
0026 #define QM1D1C0042_NUM_REG_ROWS 2
0027 
0028 static const u8
0029 reg_initval[QM1D1C0042_NUM_REG_ROWS][QM1D1C0042_NUM_REGS] = { {
0030         0x48, 0x1c, 0xa0, 0x10, 0xbc, 0xc5, 0x20, 0x33,
0031         0x06, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0032         0x00, 0xff, 0xf3, 0x00, 0x2a, 0x64, 0xa6, 0x86,
0033         0x8c, 0xcf, 0xb8, 0xf1, 0xa8, 0xf2, 0x89, 0x00
0034     }, {
0035         0x68, 0x1c, 0xc0, 0x10, 0xbc, 0xc1, 0x11, 0x33,
0036         0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0037         0x00, 0xff, 0xf3, 0x00, 0x3f, 0x25, 0x5c, 0xd6,
0038         0x55, 0xcf, 0x95, 0xf6, 0x36, 0xf2, 0x09, 0x00
0039     }
0040 };
0041 
0042 static int reg_index;
0043 
0044 static const struct qm1d1c0042_config default_cfg = {
0045     .xtal_freq = 16000,
0046     .lpf = 1,
0047     .fast_srch = 0,
0048     .lpf_wait = 20,
0049     .fast_srch_wait = 4,
0050     .normal_srch_wait = 15,
0051 };
0052 
0053 struct qm1d1c0042_state {
0054     struct qm1d1c0042_config cfg;
0055     struct i2c_client *i2c;
0056     u8 regs[QM1D1C0042_NUM_REGS];
0057 };
0058 
0059 static struct qm1d1c0042_state *cfg_to_state(struct qm1d1c0042_config *c)
0060 {
0061     return container_of(c, struct qm1d1c0042_state, cfg);
0062 }
0063 
0064 static int reg_write(struct qm1d1c0042_state *state, u8 reg, u8 val)
0065 {
0066     u8 wbuf[2] = { reg, val };
0067     int ret;
0068 
0069     ret = i2c_master_send(state->i2c, wbuf, sizeof(wbuf));
0070     if (ret >= 0 && ret < sizeof(wbuf))
0071         ret = -EIO;
0072     return (ret == sizeof(wbuf)) ? 0 : ret;
0073 }
0074 
0075 static int reg_read(struct qm1d1c0042_state *state, u8 reg, u8 *val)
0076 {
0077     struct i2c_msg msgs[2] = {
0078         {
0079             .addr = state->i2c->addr,
0080             .flags = 0,
0081             .buf = &reg,
0082             .len = 1,
0083         },
0084         {
0085             .addr = state->i2c->addr,
0086             .flags = I2C_M_RD,
0087             .buf = val,
0088             .len = 1,
0089         },
0090     };
0091     int ret;
0092 
0093     ret = i2c_transfer(state->i2c->adapter, msgs, ARRAY_SIZE(msgs));
0094     if (ret >= 0 && ret < ARRAY_SIZE(msgs))
0095         ret = -EIO;
0096     return (ret == ARRAY_SIZE(msgs)) ? 0 : ret;
0097 }
0098 
0099 
0100 static int qm1d1c0042_set_srch_mode(struct qm1d1c0042_state *state, bool fast)
0101 {
0102     if (fast)
0103         state->regs[0x03] |= 0x01; /* set fast search mode */
0104     else
0105         state->regs[0x03] &= ~0x01 & 0xff;
0106 
0107     return reg_write(state, 0x03, state->regs[0x03]);
0108 }
0109 
0110 static int qm1d1c0042_wakeup(struct qm1d1c0042_state *state)
0111 {
0112     int ret;
0113 
0114     state->regs[0x01] |= 1 << 3;             /* BB_Reg_enable */
0115     state->regs[0x01] &= (~(1 << 0)) & 0xff; /* NORMAL (wake-up) */
0116     state->regs[0x05] &= (~(1 << 3)) & 0xff; /* pfd_rst NORMAL */
0117     ret = reg_write(state, 0x01, state->regs[0x01]);
0118     if (ret == 0)
0119         ret = reg_write(state, 0x05, state->regs[0x05]);
0120 
0121     if (ret < 0)
0122         dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n",
0123             __func__, state->cfg.fe->dvb->num, state->cfg.fe->id);
0124     return ret;
0125 }
0126 
0127 /* tuner_ops */
0128 
0129 static int qm1d1c0042_set_config(struct dvb_frontend *fe, void *priv_cfg)
0130 {
0131     struct qm1d1c0042_state *state;
0132     struct qm1d1c0042_config *cfg;
0133 
0134     state = fe->tuner_priv;
0135     cfg = priv_cfg;
0136 
0137     if (cfg->fe)
0138         state->cfg.fe = cfg->fe;
0139 
0140     if (cfg->xtal_freq != QM1D1C0042_CFG_XTAL_DFLT)
0141         dev_warn(&state->i2c->dev,
0142             "(%s) changing xtal_freq not supported. ", __func__);
0143     state->cfg.xtal_freq = default_cfg.xtal_freq;
0144 
0145     state->cfg.lpf = cfg->lpf;
0146     state->cfg.fast_srch = cfg->fast_srch;
0147 
0148     if (cfg->lpf_wait != QM1D1C0042_CFG_WAIT_DFLT)
0149         state->cfg.lpf_wait = cfg->lpf_wait;
0150     else
0151         state->cfg.lpf_wait = default_cfg.lpf_wait;
0152 
0153     if (cfg->fast_srch_wait != QM1D1C0042_CFG_WAIT_DFLT)
0154         state->cfg.fast_srch_wait = cfg->fast_srch_wait;
0155     else
0156         state->cfg.fast_srch_wait = default_cfg.fast_srch_wait;
0157 
0158     if (cfg->normal_srch_wait != QM1D1C0042_CFG_WAIT_DFLT)
0159         state->cfg.normal_srch_wait = cfg->normal_srch_wait;
0160     else
0161         state->cfg.normal_srch_wait = default_cfg.normal_srch_wait;
0162     return 0;
0163 }
0164 
0165 /* divisor, vco_band parameters */
0166 /*  {maxfreq,  param1(band?), param2(div?) */
0167 static const u32 conv_table[9][3] = {
0168     { 2151000, 1, 7 },
0169     { 1950000, 1, 6 },
0170     { 1800000, 1, 5 },
0171     { 1600000, 1, 4 },
0172     { 1450000, 1, 3 },
0173     { 1250000, 1, 2 },
0174     { 1200000, 0, 7 },
0175     {  975000, 0, 6 },
0176     {  950000, 0, 0 }
0177 };
0178 
0179 static int qm1d1c0042_set_params(struct dvb_frontend *fe)
0180 {
0181     struct qm1d1c0042_state *state;
0182     u32 freq;
0183     int i, ret;
0184     u8 val, mask;
0185     u32 a, sd;
0186     s32 b;
0187 
0188     state = fe->tuner_priv;
0189     freq = fe->dtv_property_cache.frequency;
0190 
0191     state->regs[0x08] &= 0xf0;
0192     state->regs[0x08] |= 0x09;
0193 
0194     state->regs[0x13] &= 0x9f;
0195     state->regs[0x13] |= 0x20;
0196 
0197     /* div2/vco_band */
0198     val = state->regs[0x02] & 0x0f;
0199     for (i = 0; i < 8; i++)
0200         if (freq < conv_table[i][0] && freq >= conv_table[i + 1][0]) {
0201             val |= conv_table[i][1] << 7;
0202             val |= conv_table[i][2] << 4;
0203             break;
0204         }
0205     ret = reg_write(state, 0x02, val);
0206     if (ret < 0)
0207         return ret;
0208 
0209     a = DIV_ROUND_CLOSEST(freq, state->cfg.xtal_freq);
0210 
0211     state->regs[0x06] &= 0x40;
0212     state->regs[0x06] |= (a - 12) / 4;
0213     ret = reg_write(state, 0x06, state->regs[0x06]);
0214     if (ret < 0)
0215         return ret;
0216 
0217     state->regs[0x07] &= 0xf0;
0218     state->regs[0x07] |= (a - 4 * ((a - 12) / 4 + 1) - 5) & 0x0f;
0219     ret = reg_write(state, 0x07, state->regs[0x07]);
0220     if (ret < 0)
0221         return ret;
0222 
0223     /* LPF */
0224     val = state->regs[0x08];
0225     if (state->cfg.lpf) {
0226         /* LPF_CLK, LPF_FC */
0227         val &= 0xf0;
0228         val |= 0x02;
0229     }
0230     ret = reg_write(state, 0x08, val);
0231     if (ret < 0)
0232         return ret;
0233 
0234     /*
0235      * b = (freq / state->cfg.xtal_freq - a) << 20;
0236      * sd = b          (b >= 0)
0237      *      1<<22 + b  (b < 0)
0238      */
0239     b = (s32)div64_s64(((s64) freq) << 20, state->cfg.xtal_freq)
0240                - (((s64) a) << 20);
0241 
0242     if (b >= 0)
0243         sd = b;
0244     else
0245         sd = (1 << 22) + b;
0246 
0247     state->regs[0x09] &= 0xc0;
0248     state->regs[0x09] |= (sd >> 16) & 0x3f;
0249     state->regs[0x0a] = (sd >> 8) & 0xff;
0250     state->regs[0x0b] = sd & 0xff;
0251     ret = reg_write(state, 0x09, state->regs[0x09]);
0252     if (ret == 0)
0253         ret = reg_write(state, 0x0a, state->regs[0x0a]);
0254     if (ret == 0)
0255         ret = reg_write(state, 0x0b, state->regs[0x0b]);
0256     if (ret != 0)
0257         return ret;
0258 
0259     if (!state->cfg.lpf) {
0260         /* CSEL_Offset */
0261         ret = reg_write(state, 0x13, state->regs[0x13]);
0262         if (ret < 0)
0263             return ret;
0264     }
0265 
0266     /* VCO_TM, LPF_TM */
0267     mask = state->cfg.lpf ? 0x3f : 0x7f;
0268     val = state->regs[0x0c] & mask;
0269     ret = reg_write(state, 0x0c, val);
0270     if (ret < 0)
0271         return ret;
0272     usleep_range(2000, 3000);
0273     val = state->regs[0x0c] | ~mask;
0274     ret = reg_write(state, 0x0c, val);
0275     if (ret < 0)
0276         return ret;
0277 
0278     if (state->cfg.lpf)
0279         msleep(state->cfg.lpf_wait);
0280     else if (state->regs[0x03] & 0x01)
0281         msleep(state->cfg.fast_srch_wait);
0282     else
0283         msleep(state->cfg.normal_srch_wait);
0284 
0285     if (state->cfg.lpf) {
0286         /* LPF_FC */
0287         ret = reg_write(state, 0x08, 0x09);
0288         if (ret < 0)
0289             return ret;
0290 
0291         /* CSEL_Offset */
0292         ret = reg_write(state, 0x13, state->regs[0x13]);
0293         if (ret < 0)
0294             return ret;
0295     }
0296     return 0;
0297 }
0298 
0299 static int qm1d1c0042_sleep(struct dvb_frontend *fe)
0300 {
0301     struct qm1d1c0042_state *state;
0302     int ret;
0303 
0304     state = fe->tuner_priv;
0305     state->regs[0x01] &= (~(1 << 3)) & 0xff; /* BB_Reg_disable */
0306     state->regs[0x01] |= 1 << 0;             /* STDBY */
0307     state->regs[0x05] |= 1 << 3;             /* pfd_rst STANDBY */
0308     ret = reg_write(state, 0x05, state->regs[0x05]);
0309     if (ret == 0)
0310         ret = reg_write(state, 0x01, state->regs[0x01]);
0311     if (ret < 0)
0312         dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n",
0313             __func__, fe->dvb->num, fe->id);
0314     return ret;
0315 }
0316 
0317 static int qm1d1c0042_init(struct dvb_frontend *fe)
0318 {
0319     struct qm1d1c0042_state *state;
0320     u8 val;
0321     int i, ret;
0322 
0323     state = fe->tuner_priv;
0324 
0325     reg_write(state, 0x01, 0x0c);
0326     reg_write(state, 0x01, 0x0c);
0327 
0328     ret = reg_write(state, 0x01, 0x0c); /* soft reset on */
0329     if (ret < 0)
0330         goto failed;
0331     usleep_range(2000, 3000);
0332 
0333     ret = reg_write(state, 0x01, 0x1c); /* soft reset off */
0334     if (ret < 0)
0335         goto failed;
0336 
0337     /* check ID and choose initial registers corresponding ID */
0338     ret = reg_read(state, 0x00, &val);
0339     if (ret < 0)
0340         goto failed;
0341     for (reg_index = 0; reg_index < QM1D1C0042_NUM_REG_ROWS;
0342          reg_index++) {
0343         if (val == reg_initval[reg_index][0x00])
0344             break;
0345     }
0346     if (reg_index >= QM1D1C0042_NUM_REG_ROWS) {
0347         ret = -EINVAL;
0348         goto failed;
0349     }
0350     memcpy(state->regs, reg_initval[reg_index], QM1D1C0042_NUM_REGS);
0351     usleep_range(2000, 3000);
0352 
0353     state->regs[0x0c] |= 0x40;
0354     ret = reg_write(state, 0x0c, state->regs[0x0c]);
0355     if (ret < 0)
0356         goto failed;
0357     msleep(state->cfg.lpf_wait);
0358 
0359     /* set all writable registers */
0360     for (i = 1; i <= 0x0c ; i++) {
0361         ret = reg_write(state, i, state->regs[i]);
0362         if (ret < 0)
0363             goto failed;
0364     }
0365     for (i = 0x11; i < QM1D1C0042_NUM_REGS; i++) {
0366         ret = reg_write(state, i, state->regs[i]);
0367         if (ret < 0)
0368             goto failed;
0369     }
0370 
0371     ret = qm1d1c0042_wakeup(state);
0372     if (ret < 0)
0373         goto failed;
0374 
0375     ret = qm1d1c0042_set_srch_mode(state, state->cfg.fast_srch);
0376     if (ret < 0)
0377         goto failed;
0378 
0379     return ret;
0380 
0381 failed:
0382     dev_warn(&state->i2c->dev, "(%s) failed. [adap%d-fe%d]\n",
0383         __func__, fe->dvb->num, fe->id);
0384     return ret;
0385 }
0386 
0387 /* I2C driver functions */
0388 
0389 static const struct dvb_tuner_ops qm1d1c0042_ops = {
0390     .info = {
0391         .name = "Sharp QM1D1C0042",
0392 
0393         .frequency_min_hz =  950 * MHz,
0394         .frequency_max_hz = 2150 * MHz,
0395     },
0396 
0397     .init = qm1d1c0042_init,
0398     .sleep = qm1d1c0042_sleep,
0399     .set_config = qm1d1c0042_set_config,
0400     .set_params = qm1d1c0042_set_params,
0401 };
0402 
0403 
0404 static int qm1d1c0042_probe(struct i2c_client *client,
0405                 const struct i2c_device_id *id)
0406 {
0407     struct qm1d1c0042_state *state;
0408     struct qm1d1c0042_config *cfg;
0409     struct dvb_frontend *fe;
0410 
0411     state = kzalloc(sizeof(*state), GFP_KERNEL);
0412     if (!state)
0413         return -ENOMEM;
0414     state->i2c = client;
0415 
0416     cfg = client->dev.platform_data;
0417     fe = cfg->fe;
0418     fe->tuner_priv = state;
0419     qm1d1c0042_set_config(fe, cfg);
0420     memcpy(&fe->ops.tuner_ops, &qm1d1c0042_ops, sizeof(qm1d1c0042_ops));
0421 
0422     i2c_set_clientdata(client, &state->cfg);
0423     dev_info(&client->dev, "Sharp QM1D1C0042 attached.\n");
0424     return 0;
0425 }
0426 
0427 static int qm1d1c0042_remove(struct i2c_client *client)
0428 {
0429     struct qm1d1c0042_state *state;
0430 
0431     state = cfg_to_state(i2c_get_clientdata(client));
0432     state->cfg.fe->tuner_priv = NULL;
0433     kfree(state);
0434     return 0;
0435 }
0436 
0437 
0438 static const struct i2c_device_id qm1d1c0042_id[] = {
0439     {"qm1d1c0042", 0},
0440     {}
0441 };
0442 MODULE_DEVICE_TABLE(i2c, qm1d1c0042_id);
0443 
0444 static struct i2c_driver qm1d1c0042_driver = {
0445     .driver = {
0446         .name   = "qm1d1c0042",
0447     },
0448     .probe      = qm1d1c0042_probe,
0449     .remove     = qm1d1c0042_remove,
0450     .id_table   = qm1d1c0042_id,
0451 };
0452 
0453 module_i2c_driver(qm1d1c0042_driver);
0454 
0455 MODULE_DESCRIPTION("Sharp QM1D1C0042 tuner");
0456 MODULE_AUTHOR("Akihiro TSUKADA");
0457 MODULE_LICENSE("GPL");