s921.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Sharp VA3A5JZ921 One Seg Broadcast Module driver
  4. * This device is labeled as just S. 921 at the top of the frontend can
  5. *
  6. * Copyright (C) 2009-2010 Mauro Carvalho Chehab
  7. * Copyright (C) 2009-2010 Douglas Landgraf <dougsland@redhat.com>
  8. *
  9. * Developed for Leadership SBTVD 1seg device sold in Brazil
  10. *
  11. * Frontend module based on cx24123 driver, getting some info from
  12. * the old s921 driver.
  13. *
  14. * FIXME: Need to port to DVB v5.2 API
  15. */
  16. #include <linux/kernel.h>
  17. #include <asm/div64.h>
  18. #include <media/dvb_frontend.h>
  19. #include "s921.h"
  20. static int debug = 1;
  21. module_param(debug, int, 0644);
  22. MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
  23. #define rc(args...) do { \
  24. printk(KERN_ERR "s921: " args); \
  25. } while (0)
  26. #define dprintk(args...) \
  27. do { \
  28. if (debug) { \
  29. printk(KERN_DEBUG "s921: %s: ", __func__); \
  30. printk(args); \
  31. } \
  32. } while (0)
  33. struct s921_state {
  34. struct i2c_adapter *i2c;
  35. const struct s921_config *config;
  36. struct dvb_frontend frontend;
  37. /* The Demod can't easily provide these, we cache them */
  38. u32 currentfreq;
  39. };
  40. /*
  41. * Various tuner defaults need to be established for a given frequency kHz.
  42. * fixme: The bounds on the bands do not match the doc in real life.
  43. * fixme: Some of them have been moved, other might need adjustment.
  44. */
  45. static struct s921_bandselect_val {
  46. u32 freq_low;
  47. u8 band_reg;
  48. } s921_bandselect[] = {
  49. { 0, 0x7b },
  50. { 485140000, 0x5b },
  51. { 515140000, 0x3b },
  52. { 545140000, 0x1b },
  53. { 599140000, 0xfb },
  54. { 623140000, 0xdb },
  55. { 659140000, 0xbb },
  56. { 713140000, 0x9b },
  57. };
  58. struct regdata {
  59. u8 reg;
  60. u8 data;
  61. };
  62. static struct regdata s921_init[] = {
  63. { 0x01, 0x80 }, /* Probably, a reset sequence */
  64. { 0x01, 0x40 },
  65. { 0x01, 0x80 },
  66. { 0x01, 0x40 },
  67. { 0x02, 0x00 },
  68. { 0x03, 0x40 },
  69. { 0x04, 0x01 },
  70. { 0x05, 0x00 },
  71. { 0x06, 0x00 },
  72. { 0x07, 0x00 },
  73. { 0x08, 0x00 },
  74. { 0x09, 0x00 },
  75. { 0x0a, 0x00 },
  76. { 0x0b, 0x5a },
  77. { 0x0c, 0x00 },
  78. { 0x0d, 0x00 },
  79. { 0x0f, 0x00 },
  80. { 0x13, 0x1b },
  81. { 0x14, 0x80 },
  82. { 0x15, 0x40 },
  83. { 0x17, 0x70 },
  84. { 0x18, 0x01 },
  85. { 0x19, 0x12 },
  86. { 0x1a, 0x01 },
  87. { 0x1b, 0x12 },
  88. { 0x1c, 0xa0 },
  89. { 0x1d, 0x00 },
  90. { 0x1e, 0x0a },
  91. { 0x1f, 0x08 },
  92. { 0x20, 0x40 },
  93. { 0x21, 0xff },
  94. { 0x22, 0x4c },
  95. { 0x23, 0x4e },
  96. { 0x24, 0x4c },
  97. { 0x25, 0x00 },
  98. { 0x26, 0x00 },
  99. { 0x27, 0xf4 },
  100. { 0x28, 0x60 },
  101. { 0x29, 0x88 },
  102. { 0x2a, 0x40 },
  103. { 0x2b, 0x40 },
  104. { 0x2c, 0xff },
  105. { 0x2d, 0x00 },
  106. { 0x2e, 0xff },
  107. { 0x2f, 0x00 },
  108. { 0x30, 0x20 },
  109. { 0x31, 0x06 },
  110. { 0x32, 0x0c },
  111. { 0x34, 0x0f },
  112. { 0x37, 0xfe },
  113. { 0x38, 0x00 },
  114. { 0x39, 0x63 },
  115. { 0x3a, 0x10 },
  116. { 0x3b, 0x10 },
  117. { 0x47, 0x00 },
  118. { 0x49, 0xe5 },
  119. { 0x4b, 0x00 },
  120. { 0x50, 0xc0 },
  121. { 0x52, 0x20 },
  122. { 0x54, 0x5a },
  123. { 0x55, 0x5b },
  124. { 0x56, 0x40 },
  125. { 0x57, 0x70 },
  126. { 0x5c, 0x50 },
  127. { 0x5d, 0x00 },
  128. { 0x62, 0x17 },
  129. { 0x63, 0x2f },
  130. { 0x64, 0x6f },
  131. { 0x68, 0x00 },
  132. { 0x69, 0x89 },
  133. { 0x6a, 0x00 },
  134. { 0x6b, 0x00 },
  135. { 0x6c, 0x00 },
  136. { 0x6d, 0x00 },
  137. { 0x6e, 0x00 },
  138. { 0x70, 0x10 },
  139. { 0x71, 0x00 },
  140. { 0x75, 0x00 },
  141. { 0x76, 0x30 },
  142. { 0x77, 0x01 },
  143. { 0xaf, 0x00 },
  144. { 0xb0, 0xa0 },
  145. { 0xb2, 0x3d },
  146. { 0xb3, 0x25 },
  147. { 0xb4, 0x8b },
  148. { 0xb5, 0x4b },
  149. { 0xb6, 0x3f },
  150. { 0xb7, 0xff },
  151. { 0xb8, 0xff },
  152. { 0xb9, 0xfc },
  153. { 0xba, 0x00 },
  154. { 0xbb, 0x00 },
  155. { 0xbc, 0x00 },
  156. { 0xd0, 0x30 },
  157. { 0xe4, 0x84 },
  158. { 0xf0, 0x48 },
  159. { 0xf1, 0x19 },
  160. { 0xf2, 0x5a },
  161. { 0xf3, 0x8e },
  162. { 0xf4, 0x2d },
  163. { 0xf5, 0x07 },
  164. { 0xf6, 0x5a },
  165. { 0xf7, 0xba },
  166. { 0xf8, 0xd7 },
  167. };
  168. static struct regdata s921_prefreq[] = {
  169. { 0x47, 0x60 },
  170. { 0x68, 0x00 },
  171. { 0x69, 0x89 },
  172. { 0xf0, 0x48 },
  173. { 0xf1, 0x19 },
  174. };
  175. static struct regdata s921_postfreq[] = {
  176. { 0xf5, 0xae },
  177. { 0xf6, 0xb7 },
  178. { 0xf7, 0xba },
  179. { 0xf8, 0xd7 },
  180. { 0x68, 0x0a },
  181. { 0x69, 0x09 },
  182. };
  183. static int s921_i2c_writereg(struct s921_state *state,
  184. u8 i2c_addr, int reg, int data)
  185. {
  186. u8 buf[] = { reg, data };
  187. struct i2c_msg msg = {
  188. .addr = i2c_addr, .flags = 0, .buf = buf, .len = 2
  189. };
  190. int rc;
  191. rc = i2c_transfer(state->i2c, &msg, 1);
  192. if (rc != 1) {
  193. printk("%s: writereg rcor(rc == %i, reg == 0x%02x, data == 0x%02x)\n",
  194. __func__, rc, reg, data);
  195. return rc;
  196. }
  197. return 0;
  198. }
  199. static int s921_i2c_writeregdata(struct s921_state *state, u8 i2c_addr,
  200. struct regdata *rd, int size)
  201. {
  202. int i, rc;
  203. for (i = 0; i < size; i++) {
  204. rc = s921_i2c_writereg(state, i2c_addr, rd[i].reg, rd[i].data);
  205. if (rc < 0)
  206. return rc;
  207. }
  208. return 0;
  209. }
  210. static int s921_i2c_readreg(struct s921_state *state, u8 i2c_addr, u8 reg)
  211. {
  212. u8 val;
  213. int rc;
  214. struct i2c_msg msg[] = {
  215. { .addr = i2c_addr, .flags = 0, .buf = &reg, .len = 1 },
  216. { .addr = i2c_addr, .flags = I2C_M_RD, .buf = &val, .len = 1 }
  217. };
  218. rc = i2c_transfer(state->i2c, msg, 2);
  219. if (rc != 2) {
  220. rc("%s: reg=0x%x (rcor=%d)\n", __func__, reg, rc);
  221. return rc;
  222. }
  223. return val;
  224. }
  225. #define s921_readreg(state, reg) \
  226. s921_i2c_readreg(state, state->config->demod_address, reg)
  227. #define s921_writereg(state, reg, val) \
  228. s921_i2c_writereg(state, state->config->demod_address, reg, val)
  229. #define s921_writeregdata(state, regdata) \
  230. s921_i2c_writeregdata(state, state->config->demod_address, \
  231. regdata, ARRAY_SIZE(regdata))
  232. static int s921_pll_tune(struct dvb_frontend *fe)
  233. {
  234. struct dtv_frontend_properties *p = &fe->dtv_property_cache;
  235. struct s921_state *state = fe->demodulator_priv;
  236. int band, rc, i;
  237. unsigned long f_offset;
  238. u8 f_switch;
  239. u64 offset;
  240. dprintk("frequency=%i\n", p->frequency);
  241. for (band = 0; band < ARRAY_SIZE(s921_bandselect); band++)
  242. if (p->frequency < s921_bandselect[band].freq_low)
  243. break;
  244. band--;
  245. if (band < 0) {
  246. rc("%s: frequency out of range\n", __func__);
  247. return -EINVAL;
  248. }
  249. f_switch = s921_bandselect[band].band_reg;
  250. offset = ((u64)p->frequency) * 258;
  251. do_div(offset, 6000000);
  252. f_offset = ((unsigned long)offset) + 2321;
  253. rc = s921_writeregdata(state, s921_prefreq);
  254. if (rc < 0)
  255. return rc;
  256. rc = s921_writereg(state, 0xf2, (f_offset >> 8) & 0xff);
  257. if (rc < 0)
  258. return rc;
  259. rc = s921_writereg(state, 0xf3, f_offset & 0xff);
  260. if (rc < 0)
  261. return rc;
  262. rc = s921_writereg(state, 0xf4, f_switch);
  263. if (rc < 0)
  264. return rc;
  265. rc = s921_writeregdata(state, s921_postfreq);
  266. if (rc < 0)
  267. return rc;
  268. for (i = 0 ; i < 6; i++) {
  269. rc = s921_readreg(state, 0x80);
  270. dprintk("status 0x80: %02x\n", rc);
  271. }
  272. rc = s921_writereg(state, 0x01, 0x40);
  273. if (rc < 0)
  274. return rc;
  275. rc = s921_readreg(state, 0x01);
  276. dprintk("status 0x01: %02x\n", rc);
  277. rc = s921_readreg(state, 0x80);
  278. dprintk("status 0x80: %02x\n", rc);
  279. rc = s921_readreg(state, 0x80);
  280. dprintk("status 0x80: %02x\n", rc);
  281. rc = s921_readreg(state, 0x32);
  282. dprintk("status 0x32: %02x\n", rc);
  283. dprintk("pll tune band=%d, pll=%d\n", f_switch, (int)f_offset);
  284. return 0;
  285. }
  286. static int s921_initfe(struct dvb_frontend *fe)
  287. {
  288. struct s921_state *state = fe->demodulator_priv;
  289. int rc;
  290. dprintk("\n");
  291. rc = s921_writeregdata(state, s921_init);
  292. if (rc < 0)
  293. return rc;
  294. return 0;
  295. }
  296. static int s921_read_status(struct dvb_frontend *fe, enum fe_status *status)
  297. {
  298. struct s921_state *state = fe->demodulator_priv;
  299. int regstatus, rc;
  300. *status = 0;
  301. rc = s921_readreg(state, 0x81);
  302. if (rc < 0)
  303. return rc;
  304. regstatus = rc << 8;
  305. rc = s921_readreg(state, 0x82);
  306. if (rc < 0)
  307. return rc;
  308. regstatus |= rc;
  309. dprintk("status = %04x\n", regstatus);
  310. /* Full Sync - We don't know what each bit means on regs 0x81/0x82 */
  311. if ((regstatus & 0xff) == 0x40) {
  312. *status = FE_HAS_SIGNAL |
  313. FE_HAS_CARRIER |
  314. FE_HAS_VITERBI |
  315. FE_HAS_SYNC |
  316. FE_HAS_LOCK;
  317. } else if (regstatus & 0x40) {
  318. /* This is close to Full Sync, but not enough to get useful info */
  319. *status = FE_HAS_SIGNAL |
  320. FE_HAS_CARRIER |
  321. FE_HAS_VITERBI |
  322. FE_HAS_SYNC;
  323. }
  324. return 0;
  325. }
  326. static int s921_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
  327. {
  328. enum fe_status status;
  329. struct s921_state *state = fe->demodulator_priv;
  330. int rc;
  331. /* FIXME: Use the proper register for it... 0x80? */
  332. rc = s921_read_status(fe, &status);
  333. if (rc < 0)
  334. return rc;
  335. *strength = (status & FE_HAS_LOCK) ? 0xffff : 0;
  336. dprintk("strength = 0x%04x\n", *strength);
  337. rc = s921_readreg(state, 0x01);
  338. dprintk("status 0x01: %02x\n", rc);
  339. rc = s921_readreg(state, 0x80);
  340. dprintk("status 0x80: %02x\n", rc);
  341. rc = s921_readreg(state, 0x32);
  342. dprintk("status 0x32: %02x\n", rc);
  343. return 0;
  344. }
  345. static int s921_set_frontend(struct dvb_frontend *fe)
  346. {
  347. struct dtv_frontend_properties *p = &fe->dtv_property_cache;
  348. struct s921_state *state = fe->demodulator_priv;
  349. int rc;
  350. dprintk("\n");
  351. /* FIXME: We don't know how to use non-auto mode */
  352. rc = s921_pll_tune(fe);
  353. if (rc < 0)
  354. return rc;
  355. state->currentfreq = p->frequency;
  356. return 0;
  357. }
  358. static int s921_get_frontend(struct dvb_frontend *fe,
  359. struct dtv_frontend_properties *p)
  360. {
  361. struct s921_state *state = fe->demodulator_priv;
  362. /* FIXME: Probably it is possible to get it from regs f1 and f2 */
  363. p->frequency = state->currentfreq;
  364. p->delivery_system = SYS_ISDBT;
  365. return 0;
  366. }
  367. static int s921_tune(struct dvb_frontend *fe,
  368. bool re_tune,
  369. unsigned int mode_flags,
  370. unsigned int *delay,
  371. enum fe_status *status)
  372. {
  373. int rc = 0;
  374. dprintk("\n");
  375. if (re_tune)
  376. rc = s921_set_frontend(fe);
  377. if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
  378. s921_read_status(fe, status);
  379. return rc;
  380. }
  381. static enum dvbfe_algo s921_get_algo(struct dvb_frontend *fe)
  382. {
  383. return DVBFE_ALGO_HW;
  384. }
  385. static void s921_release(struct dvb_frontend *fe)
  386. {
  387. struct s921_state *state = fe->demodulator_priv;
  388. dprintk("\n");
  389. kfree(state);
  390. }
  391. static const struct dvb_frontend_ops s921_ops;
  392. struct dvb_frontend *s921_attach(const struct s921_config *config,
  393. struct i2c_adapter *i2c)
  394. {
  395. /* allocate memory for the internal state */
  396. struct s921_state *state =
  397. kzalloc(sizeof(struct s921_state), GFP_KERNEL);
  398. dprintk("\n");
  399. if (!state) {
  400. rc("Unable to kzalloc\n");
  401. return NULL;
  402. }
  403. /* setup the state */
  404. state->config = config;
  405. state->i2c = i2c;
  406. /* create dvb_frontend */
  407. memcpy(&state->frontend.ops, &s921_ops,
  408. sizeof(struct dvb_frontend_ops));
  409. state->frontend.demodulator_priv = state;
  410. return &state->frontend;
  411. }
  412. EXPORT_SYMBOL(s921_attach);
  413. static const struct dvb_frontend_ops s921_ops = {
  414. .delsys = { SYS_ISDBT },
  415. /* Use dib8000 values per default */
  416. .info = {
  417. .name = "Sharp S921",
  418. .frequency_min_hz = 470 * MHz,
  419. /*
  420. * Max should be 770MHz instead, according with Sharp docs,
  421. * but Leadership doc says it works up to 806 MHz. This is
  422. * required to get channel 69, used in Brazil
  423. */
  424. .frequency_max_hz = 806 * MHz,
  425. .caps = FE_CAN_INVERSION_AUTO |
  426. FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
  427. FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
  428. FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
  429. FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
  430. FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER |
  431. FE_CAN_HIERARCHY_AUTO,
  432. },
  433. .release = s921_release,
  434. .init = s921_initfe,
  435. .set_frontend = s921_set_frontend,
  436. .get_frontend = s921_get_frontend,
  437. .read_status = s921_read_status,
  438. .read_signal_strength = s921_read_signal_strength,
  439. .tune = s921_tune,
  440. .get_frontend_algo = s921_get_algo,
  441. };
  442. MODULE_DESCRIPTION("DVB Frontend module for Sharp S921 hardware");
  443. MODULE_AUTHOR("Mauro Carvalho Chehab");
  444. MODULE_AUTHOR("Douglas Landgraf <dougsland@redhat.com>");
  445. MODULE_LICENSE("GPL");