Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
au8522_common.c
Go to the documentation of this file.
1 /*
2  Auvitek AU8522 QAM/8VSB demodulator driver
3 
4  Copyright (C) 2008 Steven Toth <[email protected]>
5  Copyright (C) 2008 Devin Heitmueller <[email protected]>
6  Copyright (C) 2005-2008 Auvitek International, Ltd.
7  Copyright (C) 2012 Michael Krufky <[email protected]>
8 
9  This program is free software; you can redistribute it and/or modify
10  it under the terms of the GNU General Public License as published by
11  the Free Software Foundation; either version 2 of the License, or
12  (at your option) any later version.
13 
14  This program is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  GNU General Public License for more details.
18 
19  You should have received a copy of the GNU General Public License
20  along with this program; if not, write to the Free Software
21  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 
23 */
24 
25 #include <linux/i2c.h>
26 #include "dvb_frontend.h"
27 #include "au8522_priv.h"
28 
29 static int debug;
30 
31 #define dprintk(arg...)\
32  do { if (debug)\
33  printk(arg);\
34  } while (0)
35 
36 /* Despite the name "hybrid_tuner", the framework works just as well for
37  hybrid demodulators as well... */
38 static LIST_HEAD(hybrid_tuner_instance_list);
39 static DEFINE_MUTEX(au8522_list_mutex);
40 
41 /* 16 bit registers, 8 bit values */
43 {
44  int ret;
45  u8 buf[] = { (reg >> 8) | 0x80, reg & 0xff, data };
46 
47  struct i2c_msg msg = { .addr = state->config->demod_address,
48  .flags = 0, .buf = buf, .len = 3 };
49 
50  ret = i2c_transfer(state->i2c, &msg, 1);
51 
52  if (ret != 1)
53  printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, "
54  "ret == %i)\n", __func__, reg, data, ret);
55 
56  return (ret != 1) ? -1 : 0;
57 }
59 
60 u8 au8522_readreg(struct au8522_state *state, u16 reg)
61 {
62  int ret;
63  u8 b0[] = { (reg >> 8) | 0x40, reg & 0xff };
64  u8 b1[] = { 0 };
65 
66  struct i2c_msg msg[] = {
67  { .addr = state->config->demod_address, .flags = 0,
68  .buf = b0, .len = 2 },
69  { .addr = state->config->demod_address, .flags = I2C_M_RD,
70  .buf = b1, .len = 1 } };
71 
72  ret = i2c_transfer(state->i2c, msg, 2);
73 
74  if (ret != 2)
75  printk(KERN_ERR "%s: readreg error (ret == %i)\n",
76  __func__, ret);
77  return b1[0];
78 }
80 
82 {
83  struct au8522_state *state = fe->demodulator_priv;
84 
85  dprintk("%s(%d)\n", __func__, enable);
86 
87  if (state->operational_mode == AU8522_ANALOG_MODE) {
88  /* We're being asked to manage the gate even though we're
89  not in digital mode. This can occur if we get switched
90  over to analog mode before the dvb_frontend kernel thread
91  has completely shutdown */
92  return 0;
93  }
94 
95  if (enable)
96  return au8522_writereg(state, 0x106, 1);
97  else
98  return au8522_writereg(state, 0x106, 0);
99 }
101 
103 {
104  struct au8522_state *state = fe->demodulator_priv;
105 
106  dprintk("%s(%d)\n", __func__, enable);
107 
108  if (enable)
109  return au8522_writereg(state, 0x106, 1);
110  else
111  return au8522_writereg(state, 0x106, 0);
112 }
114 
115 /* Reset the demod hardware and reset all of the configuration registers
116  to a default state. */
117 int au8522_get_state(struct au8522_state **state, struct i2c_adapter *i2c,
118  u8 client_address)
119 {
120  int ret;
121 
122  mutex_lock(&au8522_list_mutex);
123  ret = hybrid_tuner_request_state(struct au8522_state, (*state),
125  i2c, client_address, "au8522");
126  mutex_unlock(&au8522_list_mutex);
127 
128  return ret;
129 }
131 
133 {
134  mutex_lock(&au8522_list_mutex);
135  if (state != NULL)
137  mutex_unlock(&au8522_list_mutex);
138 }
140 
141 static int au8522_led_gpio_enable(struct au8522_state *state, int onoff)
142 {
143  struct au8522_led_config *led_config = state->config->led_cfg;
144  u8 val;
145 
146  /* bail out if we can't control an LED */
147  if (!led_config || !led_config->gpio_output ||
148  !led_config->gpio_output_enable || !led_config->gpio_output_disable)
149  return 0;
150 
151  val = au8522_readreg(state, 0x4000 |
152  (led_config->gpio_output & ~0xc000));
153  if (onoff) {
154  /* enable GPIO output */
155  val &= ~((led_config->gpio_output_enable >> 8) & 0xff);
156  val |= (led_config->gpio_output_enable & 0xff);
157  } else {
158  /* disable GPIO output */
159  val &= ~((led_config->gpio_output_disable >> 8) & 0xff);
160  val |= (led_config->gpio_output_disable & 0xff);
161  }
162  return au8522_writereg(state, 0x8000 |
163  (led_config->gpio_output & ~0xc000), val);
164 }
165 
166 /* led = 0 | off
167  * led = 1 | signal ok
168  * led = 2 | signal strong
169  * led < 0 | only light led if leds are currently off
170  */
171 int au8522_led_ctrl(struct au8522_state *state, int led)
172 {
173  struct au8522_led_config *led_config = state->config->led_cfg;
174  int i, ret = 0;
175 
176  /* bail out if we can't control an LED */
177  if (!led_config || !led_config->gpio_leds ||
178  !led_config->num_led_states || !led_config->led_states)
179  return 0;
180 
181  if (led < 0) {
182  /* if LED is already lit, then leave it as-is */
183  if (state->led_state)
184  return 0;
185  else
186  led *= -1;
187  }
188 
189  /* toggle LED if changing state */
190  if (state->led_state != led) {
191  u8 val;
192 
193  dprintk("%s: %d\n", __func__, led);
194 
195  au8522_led_gpio_enable(state, 1);
196 
197  val = au8522_readreg(state, 0x4000 |
198  (led_config->gpio_leds & ~0xc000));
199 
200  /* start with all leds off */
201  for (i = 0; i < led_config->num_led_states; i++)
202  val &= ~led_config->led_states[i];
203 
204  /* set selected LED state */
205  if (led < led_config->num_led_states)
206  val |= led_config->led_states[led];
207  else if (led_config->num_led_states)
208  val |=
209  led_config->led_states[led_config->num_led_states - 1];
210 
211  ret = au8522_writereg(state, 0x8000 |
212  (led_config->gpio_leds & ~0xc000), val);
213  if (ret < 0)
214  return ret;
215 
216  state->led_state = led;
217 
218  if (led == 0)
219  au8522_led_gpio_enable(state, 0);
220  }
221 
222  return 0;
223 }
225 
226 int au8522_init(struct dvb_frontend *fe)
227 {
228  struct au8522_state *state = fe->demodulator_priv;
229  dprintk("%s()\n", __func__);
230 
232 
233  /* Clear out any state associated with the digital side of the
234  chip, so that when it gets powered back up it won't think
235  that it is already tuned */
236  state->current_frequency = 0;
237 
238  au8522_writereg(state, 0xa4, 1 << 5);
239 
240  au8522_i2c_gate_ctrl(fe, 1);
241 
242  return 0;
243 }
245 
246 int au8522_sleep(struct dvb_frontend *fe)
247 {
248  struct au8522_state *state = fe->demodulator_priv;
249  dprintk("%s()\n", __func__);
250 
251  /* Only power down if the digital side is currently using the chip */
252  if (state->operational_mode == AU8522_ANALOG_MODE) {
253  /* We're not in one of the expected power modes, which means
254  that the DVB thread is probably telling us to go to sleep
255  even though the analog frontend has already started using
256  the chip. So ignore the request */
257  return 0;
258  }
259 
260  /* turn off led */
261  au8522_led_ctrl(state, 0);
262 
263  /* Power down the chip */
264  au8522_writereg(state, 0xa4, 1 << 5);
265 
266  state->current_frequency = 0;
267 
268  return 0;
269 }
271 
272 module_param(debug, int, 0644);
273 MODULE_PARM_DESC(debug, "Enable verbose debug messages");
274 
275 MODULE_DESCRIPTION("Auvitek AU8522 QAM-B/ATSC Demodulator driver");
276 MODULE_AUTHOR("Steven Toth");
277 MODULE_LICENSE("GPL");