root/drivers/media/tuners/qm1d1b0004.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. lookup_cb
  2. qm1d1b0004_set_params
  3. qm1d1b0004_set_config
  4. qm1d1b0004_init
  5. qm1d1b0004_probe
  6. qm1d1b0004_remove

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Sharp QM1D1B0004 satellite tuner
   4  *
   5  * Copyright (C) 2014 Akihiro Tsukada <tskd08@gmail.com>
   6  *
   7  * based on (former) drivers/media/pci/pt1/va1j5jf8007s.c.
   8  */
   9 
  10 /*
  11  * Note:
  12  * Since the data-sheet of this tuner chip is not available,
  13  * this driver lacks some tuner_ops and config options.
  14  * In addition, the implementation might be dependent on the specific use
  15  * in the FE module: VA1J5JF8007S and/or in the product: Earthsoft PT1/PT2.
  16  */
  17 
  18 #include <linux/kernel.h>
  19 #include <linux/module.h>
  20 #include <media/dvb_frontend.h>
  21 #include "qm1d1b0004.h"
  22 
  23 /*
  24  * Tuner I/F (copied from the former va1j5jf8007s.c)
  25  * b[0] I2C addr
  26  * b[1] "0":1, BG:2, divider_quotient[7:3]:5
  27  * b[2] divider_quotient[2:0]:3, divider_remainder:5
  28  * b[3] "111":3, LPF[3:2]:2, TM:1, "0":1, REF:1
  29  * b[4] BANDX, PSC:1, LPF[1:0]:2, DIV:1, "0":1
  30  *
  31  * PLL frequency step :=
  32  *    REF == 0 -> PLL XTL frequency(4MHz) / 8
  33  *    REF == 1 -> PLL XTL frequency(4MHz) / 4
  34  *
  35  * PreScaler :=
  36  *    PSC == 0 -> x32
  37  *    PSC == 1 -> x16
  38  *
  39  * divider_quotient := (frequency / PLL frequency step) / PreScaler
  40  * divider_remainder := (frequency / PLL frequency step) % PreScaler
  41  *
  42  * LPF := LPF Frequency / 1000 / 2 - 2
  43  * LPF Frequency @ baudrate=28.86Mbps = 30000
  44  *
  45  * band (1..9)
  46  *   band 1 (freq <  986000) -> DIV:1, BANDX:5, PSC:1
  47  *   band 2 (freq < 1072000) -> DIV:1, BANDX:6, PSC:1
  48  *   band 3 (freq < 1154000) -> DIV:1, BANDX:7, PSC:0
  49  *   band 4 (freq < 1291000) -> DIV:0, BANDX:1, PSC:0
  50  *   band 5 (freq < 1447000) -> DIV:0, BANDX:2, PSC:0
  51  *   band 6 (freq < 1615000) -> DIV:0, BANDX:3, PSC:0
  52  *   band 7 (freq < 1791000) -> DIV:0, BANDX:4, PSC:0
  53  *   band 8 (freq < 1972000) -> DIV:0, BANDX:5, PSC:0
  54  *   band 9 (freq < 2150000) -> DIV:0, BANDX:6, PSC:0
  55  */
  56 
  57 #define QM1D1B0004_PSC_MASK (1 << 4)
  58 
  59 #define QM1D1B0004_XTL_FREQ 4000
  60 #define QM1D1B0004_LPF_FALLBACK 30000
  61 
  62 #if 0 /* Currently unused */
  63 static const struct qm1d1b0004_config default_cfg = {
  64         .lpf_freq = QM1D1B0004_CFG_LPF_DFLT,
  65         .half_step = false,
  66 };
  67 #endif
  68 
  69 struct qm1d1b0004_state {
  70         struct qm1d1b0004_config cfg;
  71         struct i2c_client *i2c;
  72 };
  73 
  74 
  75 struct qm1d1b0004_cb_map {
  76         u32 frequency;
  77         u8 cb;
  78 };
  79 
  80 static const struct qm1d1b0004_cb_map cb_maps[] = {
  81         {  986000, 0xb2 },
  82         { 1072000, 0xd2 },
  83         { 1154000, 0xe2 },
  84         { 1291000, 0x20 },
  85         { 1447000, 0x40 },
  86         { 1615000, 0x60 },
  87         { 1791000, 0x80 },
  88         { 1972000, 0xa0 },
  89 };
  90 
  91 static u8 lookup_cb(u32 frequency)
  92 {
  93         int i;
  94         const struct qm1d1b0004_cb_map *map;
  95 
  96         for (i = 0; i < ARRAY_SIZE(cb_maps); i++) {
  97                 map = &cb_maps[i];
  98                 if (frequency < map->frequency)
  99                         return map->cb;
 100         }
 101         return 0xc0;
 102 }
 103 
 104 static int qm1d1b0004_set_params(struct dvb_frontend *fe)
 105 {
 106         struct qm1d1b0004_state *state;
 107         u32 frequency, pll, lpf_freq;
 108         u16 word;
 109         u8 buf[4], cb, lpf;
 110         int ret;
 111 
 112         state = fe->tuner_priv;
 113         frequency = fe->dtv_property_cache.frequency;
 114 
 115         pll = QM1D1B0004_XTL_FREQ / 4;
 116         if (state->cfg.half_step)
 117                 pll /= 2;
 118         word = DIV_ROUND_CLOSEST(frequency, pll);
 119         cb = lookup_cb(frequency);
 120         if (cb & QM1D1B0004_PSC_MASK)
 121                 word = (word << 1 & ~0x1f) | (word & 0x0f);
 122 
 123         /* step.1: set frequency with BG:2, TM:0(4MHZ), LPF:4MHz */
 124         buf[0] = 0x40 | word >> 8;
 125         buf[1] = word;
 126         /* inconsisnten with the above I/F doc. maybe the doc is wrong */
 127         buf[2] = 0xe0 | state->cfg.half_step;
 128         buf[3] = cb;
 129         ret = i2c_master_send(state->i2c, buf, 4);
 130         if (ret < 0)
 131                 return ret;
 132 
 133         /* step.2: set TM:1 */
 134         buf[0] = 0xe4 | state->cfg.half_step;
 135         ret = i2c_master_send(state->i2c, buf, 1);
 136         if (ret < 0)
 137                 return ret;
 138         msleep(20);
 139 
 140         /* step.3: set LPF */
 141         lpf_freq = state->cfg.lpf_freq;
 142         if (lpf_freq == QM1D1B0004_CFG_LPF_DFLT)
 143                 lpf_freq = fe->dtv_property_cache.symbol_rate / 1000;
 144         if (lpf_freq == 0)
 145                 lpf_freq = QM1D1B0004_LPF_FALLBACK;
 146         lpf = DIV_ROUND_UP(lpf_freq, 2000) - 2;
 147         buf[0] = 0xe4 | ((lpf & 0x0c) << 1) | state->cfg.half_step;
 148         buf[1] = cb | ((lpf & 0x03) << 2);
 149         ret = i2c_master_send(state->i2c, buf, 2);
 150         if (ret < 0)
 151                 return ret;
 152 
 153         /* step.4: read PLL lock? */
 154         buf[0] = 0;
 155         ret = i2c_master_recv(state->i2c, buf, 1);
 156         if (ret < 0)
 157                 return ret;
 158         return 0;
 159 }
 160 
 161 
 162 static int qm1d1b0004_set_config(struct dvb_frontend *fe, void *priv_cfg)
 163 {
 164         struct qm1d1b0004_state *state;
 165 
 166         state = fe->tuner_priv;
 167         memcpy(&state->cfg, priv_cfg, sizeof(state->cfg));
 168         return 0;
 169 }
 170 
 171 
 172 static int qm1d1b0004_init(struct dvb_frontend *fe)
 173 {
 174         struct qm1d1b0004_state *state;
 175         u8 buf[2] = {0xf8, 0x04};
 176 
 177         state = fe->tuner_priv;
 178         if (state->cfg.half_step)
 179                 buf[0] |= 0x01;
 180 
 181         return i2c_master_send(state->i2c, buf, 2);
 182 }
 183 
 184 
 185 static const struct dvb_tuner_ops qm1d1b0004_ops = {
 186         .info = {
 187                 .name = "Sharp qm1d1b0004",
 188 
 189                 .frequency_min_hz =  950 * MHz,
 190                 .frequency_max_hz = 2150 * MHz,
 191         },
 192 
 193         .init = qm1d1b0004_init,
 194 
 195         .set_params = qm1d1b0004_set_params,
 196         .set_config = qm1d1b0004_set_config,
 197 };
 198 
 199 static int
 200 qm1d1b0004_probe(struct i2c_client *client, const struct i2c_device_id *id)
 201 {
 202         struct dvb_frontend *fe;
 203         struct qm1d1b0004_config *cfg;
 204         struct qm1d1b0004_state *state;
 205         int ret;
 206 
 207         cfg = client->dev.platform_data;
 208         fe = cfg->fe;
 209         i2c_set_clientdata(client, fe);
 210 
 211         fe->tuner_priv = kzalloc(sizeof(struct qm1d1b0004_state), GFP_KERNEL);
 212         if (!fe->tuner_priv) {
 213                 ret = -ENOMEM;
 214                 goto err_mem;
 215         }
 216 
 217         memcpy(&fe->ops.tuner_ops, &qm1d1b0004_ops, sizeof(fe->ops.tuner_ops));
 218 
 219         state = fe->tuner_priv;
 220         state->i2c = client;
 221         ret = qm1d1b0004_set_config(fe, cfg);
 222         if (ret != 0)
 223                 goto err_priv;
 224 
 225         dev_info(&client->dev, "Sharp QM1D1B0004 attached.\n");
 226         return 0;
 227 
 228 err_priv:
 229         kfree(fe->tuner_priv);
 230 err_mem:
 231         fe->tuner_priv = NULL;
 232         return ret;
 233 }
 234 
 235 static int qm1d1b0004_remove(struct i2c_client *client)
 236 {
 237         struct dvb_frontend *fe;
 238 
 239         fe = i2c_get_clientdata(client);
 240         kfree(fe->tuner_priv);
 241         fe->tuner_priv = NULL;
 242         return 0;
 243 }
 244 
 245 
 246 static const struct i2c_device_id qm1d1b0004_id[] = {
 247         {"qm1d1b0004", 0},
 248         {}
 249 };
 250 
 251 MODULE_DEVICE_TABLE(i2c, qm1d1b0004_id);
 252 
 253 static struct i2c_driver qm1d1b0004_driver = {
 254         .driver = {
 255                 .name = "qm1d1b0004",
 256         },
 257         .probe    = qm1d1b0004_probe,
 258         .remove   = qm1d1b0004_remove,
 259         .id_table = qm1d1b0004_id,
 260 };
 261 
 262 module_i2c_driver(qm1d1b0004_driver);
 263 
 264 MODULE_DESCRIPTION("Sharp QM1D1B0004");
 265 MODULE_AUTHOR("Akihiro Tsukada");
 266 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */