qm1d1b0004.c 6.0 KB

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