Merge branch 'fixes' into misc
[sfrench/cifs-2.6.git] / drivers / media / dvb-frontends / au8522_common.c
1 /*
2     Auvitek AU8522 QAM/8VSB demodulator driver
3
4     Copyright (C) 2008 Steven Toth <stoth@linuxtv.org>
5     Copyright (C) 2008 Devin Heitmueller <dheitmueller@linuxtv.org>
6     Copyright (C) 2005-2008 Auvitek International, Ltd.
7     Copyright (C) 2012 Michael Krufky <mkrufky@linuxtv.org>
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 <media/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 */
42 int au8522_writereg(struct au8522_state *state, u16 reg, u8 data)
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, ret == %i)\n",
54                        __func__, reg, data, ret);
55
56         return (ret != 1) ? -1 : 0;
57 }
58 EXPORT_SYMBOL(au8522_writereg);
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 }
79 EXPORT_SYMBOL(au8522_readreg);
80
81 int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
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 }
100 EXPORT_SYMBOL(au8522_i2c_gate_ctrl);
101
102 int au8522_analog_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
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 }
113 EXPORT_SYMBOL(au8522_analog_i2c_gate_ctrl);
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),
124                                          hybrid_tuner_instance_list,
125                                          i2c, client_address, "au8522");
126         mutex_unlock(&au8522_list_mutex);
127
128         return ret;
129 }
130 EXPORT_SYMBOL(au8522_get_state);
131
132 void au8522_release_state(struct au8522_state *state)
133 {
134         mutex_lock(&au8522_list_mutex);
135         if (state != NULL)
136                 hybrid_tuner_release_state(state);
137         mutex_unlock(&au8522_list_mutex);
138 }
139 EXPORT_SYMBOL(au8522_release_state);
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 }
224 EXPORT_SYMBOL(au8522_led_ctrl);
225
226 int au8522_init(struct dvb_frontend *fe)
227 {
228         struct au8522_state *state = fe->demodulator_priv;
229         dprintk("%s()\n", __func__);
230
231         state->operational_mode = AU8522_DIGITAL_MODE;
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         state->current_modulation = VSB_8;
238
239         au8522_writereg(state, 0xa4, 1 << 5);
240
241         au8522_i2c_gate_ctrl(fe, 1);
242
243         return 0;
244 }
245 EXPORT_SYMBOL(au8522_init);
246
247 int au8522_sleep(struct dvb_frontend *fe)
248 {
249         struct au8522_state *state = fe->demodulator_priv;
250         dprintk("%s()\n", __func__);
251
252         /* Only power down if the digital side is currently using the chip */
253         if (state->operational_mode == AU8522_ANALOG_MODE) {
254                 /* We're not in one of the expected power modes, which means
255                    that the DVB thread is probably telling us to go to sleep
256                    even though the analog frontend has already started using
257                    the chip.  So ignore the request */
258                 return 0;
259         }
260
261         /* turn off led */
262         au8522_led_ctrl(state, 0);
263
264         /* Power down the chip */
265         au8522_writereg(state, 0xa4, 1 << 5);
266
267         state->current_frequency = 0;
268
269         return 0;
270 }
271 EXPORT_SYMBOL(au8522_sleep);
272
273 module_param(debug, int, 0644);
274 MODULE_PARM_DESC(debug, "Enable verbose debug messages");
275
276 MODULE_DESCRIPTION("Auvitek AU8522 QAM-B/ATSC Demodulator driver");
277 MODULE_AUTHOR("Steven Toth");
278 MODULE_LICENSE("GPL");