lnbh25.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /*
  2. * lnbh25.c
  3. *
  4. * Driver for LNB supply and control IC LNBH25
  5. *
  6. * Copyright (C) 2014 NetUP Inc.
  7. * Copyright (C) 2014 Sergey Kozlov <serjk@netup.ru>
  8. * Copyright (C) 2014 Abylay Ospan <aospan@netup.ru>
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. */
  20. #include <linux/module.h>
  21. #include <linux/init.h>
  22. #include <linux/string.h>
  23. #include <linux/slab.h>
  24. #include "dvb_frontend.h"
  25. #include "lnbh25.h"
  26. /**
  27. * struct lnbh25_priv - LNBH25 driver private data
  28. * @i2c: pointer to the I2C adapter structure
  29. * @i2c_address: I2C address of LNBH25 SEC chip
  30. * @config: Registers configuration:
  31. * offset 0: 1st register address, always 0x02 (DATA1)
  32. * offset 1: DATA1 register value
  33. * offset 2: DATA2 register value
  34. */
  35. struct lnbh25_priv {
  36. struct i2c_adapter *i2c;
  37. u8 i2c_address;
  38. u8 config[3];
  39. };
  40. #define LNBH25_STATUS_OFL 0x1
  41. #define LNBH25_STATUS_VMON 0x4
  42. #define LNBH25_VSEL_13 0x03
  43. #define LNBH25_VSEL_18 0x0a
  44. static int lnbh25_read_vmon(struct lnbh25_priv *priv)
  45. {
  46. int i, ret;
  47. u8 addr = 0x00;
  48. u8 status[6];
  49. struct i2c_msg msg[2] = {
  50. {
  51. .addr = priv->i2c_address,
  52. .flags = 0,
  53. .len = 1,
  54. .buf = &addr
  55. }, {
  56. .addr = priv->i2c_address,
  57. .flags = I2C_M_RD,
  58. .len = sizeof(status),
  59. .buf = status
  60. }
  61. };
  62. for (i = 0; i < 2; i++) {
  63. ret = i2c_transfer(priv->i2c, &msg[i], 1);
  64. if (ret >= 0 && ret != 1)
  65. ret = -EIO;
  66. if (ret < 0) {
  67. dev_dbg(&priv->i2c->dev,
  68. "%s(): I2C transfer %d failed (%d)\n",
  69. __func__, i, ret);
  70. return ret;
  71. }
  72. }
  73. print_hex_dump_bytes("lnbh25_read_vmon: ",
  74. DUMP_PREFIX_OFFSET, status, sizeof(status));
  75. if ((status[0] & (LNBH25_STATUS_OFL | LNBH25_STATUS_VMON)) != 0) {
  76. dev_err(&priv->i2c->dev,
  77. "%s(): voltage in failure state, status reg 0x%x\n",
  78. __func__, status[0]);
  79. return -EIO;
  80. }
  81. return 0;
  82. }
  83. static int lnbh25_set_voltage(struct dvb_frontend *fe,
  84. enum fe_sec_voltage voltage)
  85. {
  86. int ret;
  87. u8 data1_reg;
  88. const char *vsel;
  89. struct lnbh25_priv *priv = fe->sec_priv;
  90. struct i2c_msg msg = {
  91. .addr = priv->i2c_address,
  92. .flags = 0,
  93. .len = sizeof(priv->config),
  94. .buf = priv->config
  95. };
  96. switch (voltage) {
  97. case SEC_VOLTAGE_OFF:
  98. data1_reg = 0x00;
  99. vsel = "Off";
  100. break;
  101. case SEC_VOLTAGE_13:
  102. data1_reg = LNBH25_VSEL_13;
  103. vsel = "13V";
  104. break;
  105. case SEC_VOLTAGE_18:
  106. data1_reg = LNBH25_VSEL_18;
  107. vsel = "18V";
  108. break;
  109. default:
  110. return -EINVAL;
  111. }
  112. priv->config[1] = data1_reg;
  113. dev_dbg(&priv->i2c->dev,
  114. "%s(): %s, I2C 0x%x write [ %02x %02x %02x ]\n",
  115. __func__, vsel, priv->i2c_address,
  116. priv->config[0], priv->config[1], priv->config[2]);
  117. ret = i2c_transfer(priv->i2c, &msg, 1);
  118. if (ret >= 0 && ret != 1)
  119. ret = -EIO;
  120. if (ret < 0) {
  121. dev_err(&priv->i2c->dev, "%s(): I2C transfer error (%d)\n",
  122. __func__, ret);
  123. return ret;
  124. }
  125. if (voltage != SEC_VOLTAGE_OFF) {
  126. msleep(120);
  127. ret = lnbh25_read_vmon(priv);
  128. } else {
  129. msleep(20);
  130. ret = 0;
  131. }
  132. return ret;
  133. }
  134. static void lnbh25_release(struct dvb_frontend *fe)
  135. {
  136. struct lnbh25_priv *priv = fe->sec_priv;
  137. dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
  138. lnbh25_set_voltage(fe, SEC_VOLTAGE_OFF);
  139. kfree(fe->sec_priv);
  140. fe->sec_priv = NULL;
  141. }
  142. struct dvb_frontend *lnbh25_attach(struct dvb_frontend *fe,
  143. struct lnbh25_config *cfg,
  144. struct i2c_adapter *i2c)
  145. {
  146. struct lnbh25_priv *priv;
  147. dev_dbg(&i2c->dev, "%s()\n", __func__);
  148. priv = kzalloc(sizeof(struct lnbh25_priv), GFP_KERNEL);
  149. if (!priv)
  150. return NULL;
  151. priv->i2c_address = (cfg->i2c_address >> 1);
  152. priv->i2c = i2c;
  153. priv->config[0] = 0x02;
  154. priv->config[1] = 0x00;
  155. priv->config[2] = cfg->data2_config;
  156. fe->sec_priv = priv;
  157. if (lnbh25_set_voltage(fe, SEC_VOLTAGE_OFF)) {
  158. dev_err(&i2c->dev,
  159. "%s(): no LNBH25 found at I2C addr 0x%02x\n",
  160. __func__, priv->i2c_address);
  161. kfree(priv);
  162. fe->sec_priv = NULL;
  163. return NULL;
  164. }
  165. fe->ops.release_sec = lnbh25_release;
  166. fe->ops.set_voltage = lnbh25_set_voltage;
  167. dev_err(&i2c->dev, "%s(): attached at I2C addr 0x%02x\n",
  168. __func__, priv->i2c_address);
  169. return fe;
  170. }
  171. EXPORT_SYMBOL(lnbh25_attach);
  172. MODULE_DESCRIPTION("ST LNBH25 driver");
  173. MODULE_AUTHOR("info@netup.ru");
  174. MODULE_LICENSE("GPL");