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"); 278