s921.c 12 KB

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