Upgrade to 4.4.50-rt62
[kvmfornfv.git] / kernel / 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 "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, "
54                        "ret == %i)\n", __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
238         au8522_writereg(state, 0xa4, 1 << 5);
239
240         au8522_i2c_gate_ctrl(fe, 1);
241
242         return 0;
243 }
244 EXPORT_SYMBOL(au8522_init);
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 }
270 EXPORT_SYMBOL(au8522_sleep);
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");