Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
isl6423.c
Go to the documentation of this file.
1 /*
2  Intersil ISL6423 SEC and LNB Power supply controller
3 
4  Copyright (C) Manu Abraham <[email protected]>
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program; if not, write to the Free Software
18  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20 
21 #include <linux/delay.h>
22 #include <linux/errno.h>
23 #include <linux/init.h>
24 #include <linux/kernel.h>
25 #include <linux/module.h>
26 #include <linux/string.h>
27 #include <linux/slab.h>
28 
29 #include "dvb_frontend.h"
30 #include "isl6423.h"
31 
32 static unsigned int verbose;
33 module_param(verbose, int, 0644);
34 MODULE_PARM_DESC(verbose, "Set Verbosity level");
35 
36 #define FE_ERROR 0
37 #define FE_NOTICE 1
38 #define FE_INFO 2
39 #define FE_DEBUG 3
40 #define FE_DEBUGREG 4
41 
42 #define dprintk(__y, __z, format, arg...) do { \
43  if (__z) { \
44  if ((verbose > FE_ERROR) && (verbose > __y)) \
45  printk(KERN_ERR "%s: " format "\n", __func__ , ##arg); \
46  else if ((verbose > FE_NOTICE) && (verbose > __y)) \
47  printk(KERN_NOTICE "%s: " format "\n", __func__ , ##arg); \
48  else if ((verbose > FE_INFO) && (verbose > __y)) \
49  printk(KERN_INFO "%s: " format "\n", __func__ , ##arg); \
50  else if ((verbose > FE_DEBUG) && (verbose > __y)) \
51  printk(KERN_DEBUG "%s: " format "\n", __func__ , ##arg); \
52  } else { \
53  if (verbose > __y) \
54  printk(format, ##arg); \
55  } \
56 } while (0)
57 
58 struct isl6423_dev {
59  const struct isl6423_config *config;
60  struct i2c_adapter *i2c;
61 
64 
65  unsigned int verbose;
66 };
67 
68 static int isl6423_write(struct isl6423_dev *isl6423, u8 reg)
69 {
70  struct i2c_adapter *i2c = isl6423->i2c;
71  u8 addr = isl6423->config->addr;
72  int err = 0;
73 
74  struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = &reg, .len = 1 };
75 
76  dprintk(FE_DEBUG, 1, "write reg %02X", reg);
77  err = i2c_transfer(i2c, &msg, 1);
78  if (err < 0)
79  goto exit;
80  return 0;
81 
82 exit:
83  dprintk(FE_ERROR, 1, "I/O error <%d>", err);
84  return err;
85 }
86 
87 static int isl6423_set_modulation(struct dvb_frontend *fe)
88 {
89  struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv;
90  const struct isl6423_config *config = isl6423->config;
91  int err = 0;
92  u8 reg_2 = 0;
93 
94  reg_2 = 0x01 << 5;
95 
96  if (config->mod_extern)
97  reg_2 |= (1 << 3);
98  else
99  reg_2 |= (1 << 4);
100 
101  err = isl6423_write(isl6423, reg_2);
102  if (err < 0)
103  goto exit;
104  return 0;
105 
106 exit:
107  dprintk(FE_ERROR, 1, "I/O error <%d>", err);
108  return err;
109 }
110 
111 static int isl6423_voltage_boost(struct dvb_frontend *fe, long arg)
112 {
113  struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv;
114  u8 reg_3 = isl6423->reg_3;
115  u8 reg_4 = isl6423->reg_4;
116  int err = 0;
117 
118  if (arg) {
119  /* EN = 1, VSPEN = 1, VBOT = 1 */
120  reg_4 |= (1 << 4);
121  reg_4 |= 0x1;
122  reg_3 |= (1 << 3);
123  } else {
124  /* EN = 1, VSPEN = 1, VBOT = 0 */
125  reg_4 |= (1 << 4);
126  reg_4 &= ~0x1;
127  reg_3 |= (1 << 3);
128  }
129  err = isl6423_write(isl6423, reg_3);
130  if (err < 0)
131  goto exit;
132 
133  err = isl6423_write(isl6423, reg_4);
134  if (err < 0)
135  goto exit;
136 
137  isl6423->reg_3 = reg_3;
138  isl6423->reg_4 = reg_4;
139 
140  return 0;
141 exit:
142  dprintk(FE_ERROR, 1, "I/O error <%d>", err);
143  return err;
144 }
145 
146 
147 static int isl6423_set_voltage(struct dvb_frontend *fe,
148  enum fe_sec_voltage voltage)
149 {
150  struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv;
151  u8 reg_3 = isl6423->reg_3;
152  u8 reg_4 = isl6423->reg_4;
153  int err = 0;
154 
155  switch (voltage) {
156  case SEC_VOLTAGE_OFF:
157  /* EN = 0 */
158  reg_4 &= ~(1 << 4);
159  break;
160 
161  case SEC_VOLTAGE_13:
162  /* EN = 1, VSPEN = 1, VTOP = 0, VBOT = 0 */
163  reg_4 |= (1 << 4);
164  reg_4 &= ~0x3;
165  reg_3 |= (1 << 3);
166  break;
167 
168  case SEC_VOLTAGE_18:
169  /* EN = 1, VSPEN = 1, VTOP = 1, VBOT = 0 */
170  reg_4 |= (1 << 4);
171  reg_4 |= 0x2;
172  reg_4 &= ~0x1;
173  reg_3 |= (1 << 3);
174  break;
175 
176  default:
177  break;
178  }
179  err = isl6423_write(isl6423, reg_3);
180  if (err < 0)
181  goto exit;
182 
183  err = isl6423_write(isl6423, reg_4);
184  if (err < 0)
185  goto exit;
186 
187  isl6423->reg_3 = reg_3;
188  isl6423->reg_4 = reg_4;
189 
190  return 0;
191 exit:
192  dprintk(FE_ERROR, 1, "I/O error <%d>", err);
193  return err;
194 }
195 
196 static int isl6423_set_current(struct dvb_frontend *fe)
197 {
198  struct isl6423_dev *isl6423 = (struct isl6423_dev *) fe->sec_priv;
199  u8 reg_3 = isl6423->reg_3;
200  const struct isl6423_config *config = isl6423->config;
201  int err = 0;
202 
203  switch (config->current_max) {
204  case SEC_CURRENT_275m:
205  /* 275mA */
206  /* ISELH = 0, ISELL = 0 */
207  reg_3 &= ~0x3;
208  break;
209 
210  case SEC_CURRENT_515m:
211  /* 515mA */
212  /* ISELH = 0, ISELL = 1 */
213  reg_3 &= ~0x2;
214  reg_3 |= 0x1;
215  break;
216 
217  case SEC_CURRENT_635m:
218  /* 635mA */
219  /* ISELH = 1, ISELL = 0 */
220  reg_3 &= ~0x1;
221  reg_3 |= 0x2;
222  break;
223 
224  case SEC_CURRENT_800m:
225  /* 800mA */
226  /* ISELH = 1, ISELL = 1 */
227  reg_3 |= 0x3;
228  break;
229  }
230 
231  err = isl6423_write(isl6423, reg_3);
232  if (err < 0)
233  goto exit;
234 
235  switch (config->curlim) {
236  case SEC_CURRENT_LIM_ON:
237  /* DCL = 0 */
238  reg_3 &= ~0x10;
239  break;
240 
241  case SEC_CURRENT_LIM_OFF:
242  /* DCL = 1 */
243  reg_3 |= 0x10;
244  break;
245  }
246 
247  err = isl6423_write(isl6423, reg_3);
248  if (err < 0)
249  goto exit;
250 
251  isl6423->reg_3 = reg_3;
252 
253  return 0;
254 exit:
255  dprintk(FE_ERROR, 1, "I/O error <%d>", err);
256  return err;
257 }
258 
259 static void isl6423_release(struct dvb_frontend *fe)
260 {
261  isl6423_set_voltage(fe, SEC_VOLTAGE_OFF);
262 
263  kfree(fe->sec_priv);
264  fe->sec_priv = NULL;
265 }
266 
268  struct i2c_adapter *i2c,
269  const struct isl6423_config *config)
270 {
271  struct isl6423_dev *isl6423;
272 
273  isl6423 = kzalloc(sizeof(struct isl6423_dev), GFP_KERNEL);
274  if (!isl6423)
275  return NULL;
276 
277  isl6423->config = config;
278  isl6423->i2c = i2c;
279  fe->sec_priv = isl6423;
280 
281  /* SR3H = 0, SR3M = 1, SR3L = 0 */
282  isl6423->reg_3 = 0x02 << 5;
283  /* SR4H = 0, SR4M = 1, SR4L = 1 */
284  isl6423->reg_4 = 0x03 << 5;
285 
286  if (isl6423_set_current(fe))
287  goto exit;
288 
289  if (isl6423_set_modulation(fe))
290  goto exit;
291 
292  fe->ops.release_sec = isl6423_release;
293  fe->ops.set_voltage = isl6423_set_voltage;
294  fe->ops.enable_high_lnb_voltage = isl6423_voltage_boost;
295  isl6423->verbose = verbose;
296 
297  return fe;
298 
299 exit:
300  kfree(isl6423);
301  fe->sec_priv = NULL;
302  return NULL;
303 }
305 
306 MODULE_DESCRIPTION("ISL6423 SEC");
307 MODULE_AUTHOR("Manu Abraham");
308 MODULE_LICENSE("GPL");