1/* 2 tm6000-core.c - driver for TM5600/TM6000/TM6010 USB video capture devices 3 4 Copyright (C) 2006-2007 Mauro Carvalho Chehab <mchehab@infradead.org> 5 6 Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com> 7 - DVB-T support 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 version 2 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 */ 22 23#include <linux/module.h> 24#include <linux/kernel.h> 25#include <linux/slab.h> 26#include <linux/usb.h> 27#include <linux/i2c.h> 28#include "tm6000.h" 29#include "tm6000-regs.h" 30#include <media/v4l2-common.h> 31#include <media/tuner.h> 32 33#define USB_TIMEOUT 5*HZ /* ms */ 34 35int tm6000_read_write_usb(struct tm6000_core *dev, u8 req_type, u8 req, 36 u16 value, u16 index, u8 *buf, u16 len) 37{ 38 int ret, i; 39 unsigned int pipe; 40 static int ini = 0, last = 0, n = 0; 41 u8 *data = NULL; 42 43 if (len) 44 data = kzalloc(len, GFP_KERNEL); 45 46 47 if (req_type & USB_DIR_IN) 48 pipe = usb_rcvctrlpipe(dev->udev, 0); 49 else { 50 pipe = usb_sndctrlpipe(dev->udev, 0); 51 memcpy(data, buf, len); 52 } 53 54 if (tm6000_debug & V4L2_DEBUG_I2C) { 55 if (!ini) 56 last = ini = jiffies; 57 58 printk("%06i (dev %p, pipe %08x): ", n, dev->udev, pipe); 59 60 printk("%s: %06u ms %06u ms %02x %02x %02x %02x %02x %02x %02x %02x ", 61 (req_type & USB_DIR_IN) ? " IN" : "OUT", 62 jiffies_to_msecs(jiffies-last), 63 jiffies_to_msecs(jiffies-ini), 64 req_type, req, value&0xff, value>>8, index&0xff, 65 index>>8, len&0xff, len>>8); 66 last = jiffies; 67 n++; 68 69 if (!(req_type & USB_DIR_IN)) { 70 printk(">>> "); 71 for (i = 0; i < len; i++) 72 printk(" %02x", buf[i]); 73 printk("\n"); 74 } 75 } 76 77 ret = usb_control_msg(dev->udev, pipe, req, req_type, value, index, 78 data, len, USB_TIMEOUT); 79 80 if (req_type & USB_DIR_IN) 81 memcpy(buf, data, len); 82 83 if (tm6000_debug & V4L2_DEBUG_I2C) { 84 if (ret < 0) { 85 if (req_type & USB_DIR_IN) 86 printk("<<< (len=%d)\n", len); 87 88 printk("%s: Error #%d\n", __FUNCTION__, ret); 89 } else if (req_type & USB_DIR_IN) { 90 printk("<<< "); 91 for (i = 0; i < len; i++) 92 printk(" %02x", buf[i]); 93 printk("\n"); 94 } 95 } 96 97 kfree(data); 98 99 msleep(5); 100 101 return ret; 102} 103 104int tm6000_set_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index) 105{ 106 return 107 tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR, 108 req, value, index, NULL, 0); 109} 110EXPORT_SYMBOL_GPL(tm6000_set_reg); 111 112int tm6000_get_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index) 113{ 114 int rc; 115 u8 buf[1]; 116 117 rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req, 118 value, index, buf, 1); 119 120 if (rc < 0) 121 return rc; 122 123 return *buf; 124} 125EXPORT_SYMBOL_GPL(tm6000_get_reg); 126 127int tm6000_get_reg16(struct tm6000_core *dev, u8 req, u16 value, u16 index) 128{ 129 int rc; 130 u8 buf[2]; 131 132 rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req, 133 value, index, buf, 2); 134 135 if (rc < 0) 136 return rc; 137 138 return buf[1]|buf[0]<<8; 139} 140 141int tm6000_get_reg32(struct tm6000_core *dev, u8 req, u16 value, u16 index) 142{ 143 int rc; 144 u8 buf[4]; 145 146 rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req, 147 value, index, buf, 4); 148 149 if (rc < 0) 150 return rc; 151 152 return buf[3] | buf[2] << 8 | buf[1] << 16 | buf[0] << 24; 153} 154 155int tm6000_i2c_reset(struct tm6000_core *dev, u16 tsleep) 156{ 157 int rc; 158 159 rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_CLK, 0); 160 if (rc < 0) 161 return rc; 162 163 msleep(tsleep); 164 165 rc = tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_CLK, 1); 166 msleep(tsleep); 167 168 return rc; 169} 170 171void tm6000_set_fourcc_format(struct tm6000_core *dev) 172{ 173 if (dev->dev_type == TM6010) { 174 int val; 175 176 val = tm6000_get_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0) & 0xfc; 177 if (dev->fourcc == V4L2_PIX_FMT_UYVY) 178 tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val); 179 else 180 tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val | 1); 181 } else { 182 if (dev->fourcc == V4L2_PIX_FMT_UYVY) 183 tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0xd0); 184 else 185 tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0x90); 186 } 187} 188 189int tm6000_init_analog_mode(struct tm6000_core *dev) 190{ 191 if (dev->dev_type == TM6010) { 192 int val; 193 194 /* Enable video */ 195 val = tm6000_get_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0); 196 val |= 0x60; 197 tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val); 198 val = tm6000_get_reg(dev, 199 TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0); 200 val &= ~0x40; 201 tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, val); 202 203 /* Init teletext */ 204 tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01); 205 tm6000_set_reg(dev, TM6010_REQ07_R41_TELETEXT_VBI_CODE1, 0x27); 206 tm6000_set_reg(dev, TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL, 0x55); 207 tm6000_set_reg(dev, TM6010_REQ07_R43_VBI_DATA_TYPE_LINE7, 0x66); 208 tm6000_set_reg(dev, TM6010_REQ07_R44_VBI_DATA_TYPE_LINE8, 0x66); 209 tm6000_set_reg(dev, TM6010_REQ07_R45_VBI_DATA_TYPE_LINE9, 0x66); 210 tm6000_set_reg(dev, 211 TM6010_REQ07_R46_VBI_DATA_TYPE_LINE10, 0x66); 212 tm6000_set_reg(dev, 213 TM6010_REQ07_R47_VBI_DATA_TYPE_LINE11, 0x66); 214 tm6000_set_reg(dev, 215 TM6010_REQ07_R48_VBI_DATA_TYPE_LINE12, 0x66); 216 tm6000_set_reg(dev, 217 TM6010_REQ07_R49_VBI_DATA_TYPE_LINE13, 0x66); 218 tm6000_set_reg(dev, 219 TM6010_REQ07_R4A_VBI_DATA_TYPE_LINE14, 0x66); 220 tm6000_set_reg(dev, 221 TM6010_REQ07_R4B_VBI_DATA_TYPE_LINE15, 0x66); 222 tm6000_set_reg(dev, 223 TM6010_REQ07_R4C_VBI_DATA_TYPE_LINE16, 0x66); 224 tm6000_set_reg(dev, 225 TM6010_REQ07_R4D_VBI_DATA_TYPE_LINE17, 0x66); 226 tm6000_set_reg(dev, 227 TM6010_REQ07_R4E_VBI_DATA_TYPE_LINE18, 0x66); 228 tm6000_set_reg(dev, 229 TM6010_REQ07_R4F_VBI_DATA_TYPE_LINE19, 0x66); 230 tm6000_set_reg(dev, 231 TM6010_REQ07_R50_VBI_DATA_TYPE_LINE20, 0x66); 232 tm6000_set_reg(dev, 233 TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21, 0x66); 234 tm6000_set_reg(dev, 235 TM6010_REQ07_R52_VBI_DATA_TYPE_LINE22, 0x66); 236 tm6000_set_reg(dev, 237 TM6010_REQ07_R53_VBI_DATA_TYPE_LINE23, 0x00); 238 tm6000_set_reg(dev, 239 TM6010_REQ07_R54_VBI_DATA_TYPE_RLINES, 0x00); 240 tm6000_set_reg(dev, 241 TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN, 0x01); 242 tm6000_set_reg(dev, 243 TM6010_REQ07_R56_VBI_LOOP_FILTER_I_GAIN, 0x00); 244 tm6000_set_reg(dev, 245 TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN, 0x02); 246 tm6000_set_reg(dev, TM6010_REQ07_R58_VBI_CAPTION_DTO1, 0x35); 247 tm6000_set_reg(dev, TM6010_REQ07_R59_VBI_CAPTION_DTO0, 0xa0); 248 tm6000_set_reg(dev, TM6010_REQ07_R5A_VBI_TELETEXT_DTO1, 0x11); 249 tm6000_set_reg(dev, TM6010_REQ07_R5B_VBI_TELETEXT_DTO0, 0x4c); 250 tm6000_set_reg(dev, TM6010_REQ07_R40_TELETEXT_VBI_CODE0, 0x01); 251 tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x00); 252 253 254 /* Init audio */ 255 tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x00); 256 tm6000_set_reg(dev, TM6010_REQ08_R02_A_FIX_GAIN_CTRL, 0x04); 257 tm6000_set_reg(dev, TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00); 258 tm6000_set_reg(dev, TM6010_REQ08_R04_A_SIF_AMP_CTRL, 0xa0); 259 tm6000_set_reg(dev, TM6010_REQ08_R05_A_STANDARD_MOD, 0x05); 260 tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x06); 261 tm6000_set_reg(dev, TM6010_REQ08_R07_A_LEFT_VOL, 0x00); 262 tm6000_set_reg(dev, TM6010_REQ08_R08_A_RIGHT_VOL, 0x00); 263 tm6000_set_reg(dev, TM6010_REQ08_R09_A_MAIN_VOL, 0x08); 264 tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, 0x91); 265 tm6000_set_reg(dev, TM6010_REQ08_R0B_A_ASD_THRES1, 0x20); 266 tm6000_set_reg(dev, TM6010_REQ08_R0C_A_ASD_THRES2, 0x12); 267 tm6000_set_reg(dev, TM6010_REQ08_R0D_A_AMD_THRES, 0x20); 268 tm6000_set_reg(dev, TM6010_REQ08_R0E_A_MONO_THRES1, 0xf0); 269 tm6000_set_reg(dev, TM6010_REQ08_R0F_A_MONO_THRES2, 0x80); 270 tm6000_set_reg(dev, TM6010_REQ08_R10_A_MUTE_THRES1, 0xc0); 271 tm6000_set_reg(dev, TM6010_REQ08_R11_A_MUTE_THRES2, 0x80); 272 tm6000_set_reg(dev, TM6010_REQ08_R12_A_AGC_U, 0x12); 273 tm6000_set_reg(dev, TM6010_REQ08_R13_A_AGC_ERR_T, 0xfe); 274 tm6000_set_reg(dev, TM6010_REQ08_R14_A_AGC_GAIN_INIT, 0x20); 275 tm6000_set_reg(dev, TM6010_REQ08_R15_A_AGC_STEP_THR, 0x14); 276 tm6000_set_reg(dev, TM6010_REQ08_R16_A_AGC_GAIN_MAX, 0xfe); 277 tm6000_set_reg(dev, TM6010_REQ08_R17_A_AGC_GAIN_MIN, 0x01); 278 tm6000_set_reg(dev, TM6010_REQ08_R18_A_TR_CTRL, 0xa0); 279 tm6000_set_reg(dev, TM6010_REQ08_R19_A_FH_2FH_GAIN, 0x32); 280 tm6000_set_reg(dev, TM6010_REQ08_R1A_A_NICAM_SER_MAX, 0x64); 281 tm6000_set_reg(dev, TM6010_REQ08_R1B_A_NICAM_SER_MIN, 0x20); 282 tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0x1c, 0x00); 283 tm6000_set_reg(dev, REQ_08_SET_GET_AVREG_BIT, 0x1d, 0x00); 284 tm6000_set_reg(dev, TM6010_REQ08_R1E_A_GAIN_DEEMPH_OUT, 0x13); 285 tm6000_set_reg(dev, TM6010_REQ08_R1F_A_TEST_INTF_SEL, 0x00); 286 tm6000_set_reg(dev, TM6010_REQ08_R20_A_TEST_PIN_SEL, 0x00); 287 tm6000_set_reg(dev, TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf3); 288 tm6000_set_reg(dev, TM6010_REQ08_R06_A_SOUND_MOD, 0x00); 289 tm6000_set_reg(dev, TM6010_REQ08_R01_A_INIT, 0x80); 290 291 } else { 292 /* Enables soft reset */ 293 tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01); 294 295 if (dev->scaler) 296 tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x20); 297 else /* Enable Hfilter and disable TS Drop err */ 298 tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x80); 299 300 tm6000_set_reg(dev, TM6010_REQ07_RC3_HSTART1, 0x88); 301 tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0x23); 302 tm6000_set_reg(dev, TM6010_REQ07_RD1_ADDR_FOR_REQ1, 0xc0); 303 tm6000_set_reg(dev, TM6010_REQ07_RD2_ADDR_FOR_REQ2, 0xd8); 304 tm6000_set_reg(dev, TM6010_REQ07_RD6_ENDP_REQ1_REQ2, 0x06); 305 tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT0, 0x1f); 306 307 /* AP Software reset */ 308 tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x08); 309 tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x00); 310 311 tm6000_set_fourcc_format(dev); 312 313 /* Disables soft reset */ 314 tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x00); 315 316 /* E3: Select input 0 - TV tuner */ 317 tm6000_set_reg(dev, TM6010_REQ07_RE3_OUT_SEL1, 0x00); 318 tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xeb, 0x60); 319 320 /* This controls input */ 321 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_2, 0x0); 322 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_3, 0x01); 323 } 324 msleep(20); 325 326 /* Tuner firmware can now be loaded */ 327 328 struct v4l2_frequency f; 329 mutex_lock(&dev->lock); 330 f.frequency = dev->freq; 331 v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f); 332 mutex_unlock(&dev->lock); 333 334 msleep(100); 335 tm6000_set_standard(dev, &dev->norm); 336 tm6000_set_audio_bitrate(dev, 48000); 337 338 /* switch dvb led off */ 339 if (dev->gpio.dvb_led) { 340 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 341 dev->gpio.dvb_led, 0x01); 342 } 343 344 return 0; 345} 346 347int tm6000_init_digital_mode(struct tm6000_core *dev) 348{ 349 if (dev->dev_type == TM6010) { 350 int val; 351 u8 buf[2]; 352 353 /* digital init */ 354 val = tm6000_get_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0); 355 val &= ~0x60; 356 tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val); 357 val = tm6000_get_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0); 358 val |= 0x40; 359 tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, val); 360 tm6000_set_reg(dev, TM6010_REQ07_RFE_POWER_DOWN, 0x28); 361 tm6000_set_reg(dev, TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xfc); 362 tm6000_set_reg(dev, TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0xff); 363 tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfe); 364 tm6000_read_write_usb(dev, 0xc0, 0x0e, 0x00c2, 0x0008, buf, 2); 365 printk(KERN_INFO"buf %#x %#x\n", buf[0], buf[1]); 366 } else { 367 tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x08); 368 tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x00); 369 tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01); 370 tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT0, 0x08); 371 tm6000_set_reg(dev, TM6010_REQ07_RE2_OUT_SEL2, 0x0c); 372 tm6000_set_reg(dev, TM6010_REQ07_RE8_TYPESEL_MOS_I2S, 0xff); 373 tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0x00eb, 0xd8); 374 tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x40); 375 tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0xd0); 376 tm6000_set_reg(dev, TM6010_REQ07_RC3_HSTART1, 0x09); 377 tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0x37); 378 tm6000_set_reg(dev, TM6010_REQ07_RD1_ADDR_FOR_REQ1, 0xd8); 379 tm6000_set_reg(dev, TM6010_REQ07_RD2_ADDR_FOR_REQ2, 0xc0); 380 tm6000_set_reg(dev, TM6010_REQ07_RD6_ENDP_REQ1_REQ2, 0x60); 381 382 tm6000_set_reg(dev, TM6010_REQ07_RE2_OUT_SEL2, 0x0c); 383 tm6000_set_reg(dev, TM6010_REQ07_RE8_TYPESEL_MOS_I2S, 0xff); 384 tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0x00eb, 0x08); 385 msleep(50); 386 387 tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00); 388 msleep(50); 389 tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x01); 390 msleep(50); 391 tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00); 392 msleep(100); 393 } 394 395 /* switch dvb led on */ 396 if (dev->gpio.dvb_led) { 397 tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, 398 dev->gpio.dvb_led, 0x00); 399 } 400 401 return 0; 402} 403EXPORT_SYMBOL(tm6000_init_digital_mode); 404 405struct reg_init { 406 u8 req; 407 u8 reg; 408 u8 val; 409}; 410 411/* The meaning of those initializations are unknown */ 412struct reg_init tm6000_init_tab[] = { 413 /* REG VALUE */ 414 { TM6010_REQ07_RD8_IR_PULSE_CNT0, 0x1f }, 415 { TM6010_REQ07_RFF_SOFT_RESET, 0x08 }, 416 { TM6010_REQ07_RFF_SOFT_RESET, 0x00 }, 417 { TM6010_REQ07_RD5_POWERSAVE, 0x4f }, 418 { TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0x23 }, 419 { TM6010_REQ07_RD8_IR_WAKEUP_ADD, 0x08 }, 420 { TM6010_REQ07_RE2_OUT_SEL2, 0x00 }, 421 { TM6010_REQ07_RE3_OUT_SEL1, 0x10 }, 422 { TM6010_REQ07_RE5_REMOTE_WAKEUP, 0x00 }, 423 { TM6010_REQ07_RE8_TYPESEL_MOS_I2S, 0x00 }, 424 { REQ_07_SET_GET_AVREG, 0xeb, 0x64 }, /* 48000 bits/sample, external input */ 425 { REQ_07_SET_GET_AVREG, 0xee, 0xc2 }, 426 { TM6010_REQ07_R3F_RESET, 0x01 }, /* Start of soft reset */ 427 { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00 }, 428 { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x07 }, 429 { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, 430 { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 }, 431 { TM6010_REQ07_R05_NOISE_THRESHOLD, 0x64 }, 432 { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01 }, 433 { TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, 0x82 }, 434 { TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, 0x36 }, 435 { TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, 0x50 }, 436 { TM6010_REQ07_R0C_CHROMA_AGC_CONTROL, 0x6a }, 437 { TM6010_REQ07_R11_AGC_PEAK_CONTROL, 0xc9 }, 438 { TM6010_REQ07_R12_AGC_GATE_STARTH, 0x07 }, 439 { TM6010_REQ07_R13_AGC_GATE_STARTL, 0x3b }, 440 { TM6010_REQ07_R14_AGC_GATE_WIDTH, 0x47 }, 441 { TM6010_REQ07_R15_AGC_BP_DELAY, 0x6f }, 442 { TM6010_REQ07_R17_HLOOP_MAXSTATE, 0xcd }, 443 { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e }, 444 { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b }, 445 { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 }, 446 { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 }, 447 { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, 448 { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, 449 { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, 450 { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, 451 { TM6010_REQ07_R20_HSYNC_RISING_EDGE_TIME, 0x3c }, 452 { TM6010_REQ07_R21_HSYNC_PHASE_OFFSET, 0x3c }, 453 { TM6010_REQ07_R2D_CHROMA_BURST_END, 0x48 }, 454 { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 }, 455 { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 }, 456 { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 }, 457 { TM6010_REQ07_R32_VSYNC_HLOCK_MIN, 0x74 }, 458 { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c }, 459 { TM6010_REQ07_R34_VSYNC_AGC_MIN, 0x74 }, 460 { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, 461 { TM6010_REQ07_R36_VSYNC_VBI_MIN, 0x7a }, 462 { TM6010_REQ07_R37_VSYNC_VBI_MAX, 0x26 }, 463 { TM6010_REQ07_R38_VSYNC_THRESHOLD, 0x40 }, 464 { TM6010_REQ07_R39_VSYNC_TIME_CONSTANT, 0x0a }, 465 { TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL, 0x55 }, 466 { TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21, 0x11 }, 467 { TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN, 0x01 }, 468 { TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN, 0x02 }, 469 { TM6010_REQ07_R58_VBI_CAPTION_DTO1, 0x35 }, 470 { TM6010_REQ07_R59_VBI_CAPTION_DTO0, 0xa0 }, 471 { TM6010_REQ07_R80_COMB_FILTER_TRESHOLD, 0x15 }, 472 { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 }, 473 { TM6010_REQ07_RC1_TRESHOLD, 0xd0 }, 474 { TM6010_REQ07_RC3_HSTART1, 0x88 }, 475 { TM6010_REQ07_R3F_RESET, 0x00 }, /* End of the soft reset */ 476 { TM6010_REQ05_R18_IMASK7, 0x00 }, 477}; 478 479struct reg_init tm6010_init_tab[] = { 480 { TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x00 }, 481 { TM6010_REQ07_RC4_HSTART0, 0xa0 }, 482 { TM6010_REQ07_RC6_HEND0, 0x40 }, 483 { TM6010_REQ07_RCA_VEND0, 0x31 }, 484 { TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0xe1 }, 485 { TM6010_REQ07_RE0_DVIDEO_SOURCE, 0x03 }, 486 { TM6010_REQ07_RFE_POWER_DOWN, 0x7f }, 487 488 { TM6010_REQ08_RE2_POWER_DOWN_CTRL1, 0xf0 }, 489 { TM6010_REQ08_RE3_ADC_IN1_SEL, 0xf4 }, 490 { TM6010_REQ08_RE4_ADC_IN2_SEL, 0xf8 }, 491 { TM6010_REQ08_RE6_POWER_DOWN_CTRL2, 0x00 }, 492 { TM6010_REQ08_REA_BUFF_DRV_CTRL, 0xf2 }, 493 { TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0 }, 494 { TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2 }, 495 { TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x60 }, 496 { TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc }, 497 498 { TM6010_REQ07_R3F_RESET, 0x01 }, 499 { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00 }, 500 { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x07 }, 501 { TM6010_REQ07_R02_VIDEO_CONTROL2, 0x5f }, 502 { TM6010_REQ07_R03_YC_SEP_CONTROL, 0x00 }, 503 { TM6010_REQ07_R05_NOISE_THRESHOLD, 0x64 }, 504 { TM6010_REQ07_R07_OUTPUT_CONTROL, 0x01 }, 505 { TM6010_REQ07_R08_LUMA_CONTRAST_ADJ, 0x82 }, 506 { TM6010_REQ07_R09_LUMA_BRIGHTNESS_ADJ, 0x36 }, 507 { TM6010_REQ07_R0A_CHROMA_SATURATION_ADJ, 0x50 }, 508 { TM6010_REQ07_R0C_CHROMA_AGC_CONTROL, 0x6a }, 509 { TM6010_REQ07_R11_AGC_PEAK_CONTROL, 0xc9 }, 510 { TM6010_REQ07_R12_AGC_GATE_STARTH, 0x07 }, 511 { TM6010_REQ07_R13_AGC_GATE_STARTL, 0x3b }, 512 { TM6010_REQ07_R14_AGC_GATE_WIDTH, 0x47 }, 513 { TM6010_REQ07_R15_AGC_BP_DELAY, 0x6f }, 514 { TM6010_REQ07_R17_HLOOP_MAXSTATE, 0xcd }, 515 { TM6010_REQ07_R18_CHROMA_DTO_INCREMENT3, 0x1e }, 516 { TM6010_REQ07_R19_CHROMA_DTO_INCREMENT2, 0x8b }, 517 { TM6010_REQ07_R1A_CHROMA_DTO_INCREMENT1, 0xa2 }, 518 { TM6010_REQ07_R1B_CHROMA_DTO_INCREMENT0, 0xe9 }, 519 { TM6010_REQ07_R1C_HSYNC_DTO_INCREMENT3, 0x1c }, 520 { TM6010_REQ07_R1D_HSYNC_DTO_INCREMENT2, 0xcc }, 521 { TM6010_REQ07_R1E_HSYNC_DTO_INCREMENT1, 0xcc }, 522 { TM6010_REQ07_R1F_HSYNC_DTO_INCREMENT0, 0xcd }, 523 { TM6010_REQ07_R20_HSYNC_RISING_EDGE_TIME, 0x3c }, 524 { TM6010_REQ07_R21_HSYNC_PHASE_OFFSET, 0x3c }, 525 { TM6010_REQ07_R2D_CHROMA_BURST_END, 0x48 }, 526 { TM6010_REQ07_R2E_ACTIVE_VIDEO_HSTART, 0x88 }, 527 { TM6010_REQ07_R30_ACTIVE_VIDEO_VSTART, 0x22 }, 528 { TM6010_REQ07_R31_ACTIVE_VIDEO_VHIGHT, 0x61 }, 529 { TM6010_REQ07_R32_VSYNC_HLOCK_MIN, 0x74 }, 530 { TM6010_REQ07_R33_VSYNC_HLOCK_MAX, 0x1c }, 531 { TM6010_REQ07_R34_VSYNC_AGC_MIN, 0x74 }, 532 { TM6010_REQ07_R35_VSYNC_AGC_MAX, 0x1c }, 533 { TM6010_REQ07_R36_VSYNC_VBI_MIN, 0x7a }, 534 { TM6010_REQ07_R37_VSYNC_VBI_MAX, 0x26 }, 535 { TM6010_REQ07_R38_VSYNC_THRESHOLD, 0x40 }, 536 { TM6010_REQ07_R39_VSYNC_TIME_CONSTANT, 0x0a }, 537 { TM6010_REQ07_R42_VBI_DATA_HIGH_LEVEL, 0x55 }, 538 { TM6010_REQ07_R51_VBI_DATA_TYPE_LINE21, 0x11 }, 539 { TM6010_REQ07_R55_VBI_LOOP_FILTER_GAIN, 0x01 }, 540 { TM6010_REQ07_R57_VBI_LOOP_FILTER_P_GAIN, 0x02 }, 541 { TM6010_REQ07_R58_VBI_CAPTION_DTO1, 0x35 }, 542 { TM6010_REQ07_R59_VBI_CAPTION_DTO0, 0xa0 }, 543 { TM6010_REQ07_R80_COMB_FILTER_TRESHOLD, 0x15 }, 544 { TM6010_REQ07_R82_COMB_FILTER_CONFIG, 0x42 }, 545 { TM6010_REQ07_RC1_TRESHOLD, 0xd0 }, 546 { TM6010_REQ07_RC3_HSTART1, 0x88 }, 547 { TM6010_REQ07_R3F_RESET, 0x00 }, 548 549 { TM6010_REQ05_R18_IMASK7, 0x00 }, 550 551 { TM6010_REQ07_RD8_IR_LEADER1, 0xaa }, 552 { TM6010_REQ07_RD8_IR_LEADER0, 0x30 }, 553 { TM6010_REQ07_RD8_IR_PULSE_CNT1, 0x20 }, 554 { TM6010_REQ07_RD8_IR_PULSE_CNT0, 0xd0 }, 555 { REQ_04_EN_DISABLE_MCU_INT, 0x02, 0x00 }, 556 { TM6010_REQ07_RD8_IR, 0x2f }, 557 558 /* set remote wakeup key:any key wakeup */ 559 { TM6010_REQ07_RE5_REMOTE_WAKEUP, 0xfe }, 560 { TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0xff }, 561}; 562 563int tm6000_init(struct tm6000_core *dev) 564{ 565 int board, rc = 0, i, size; 566 struct reg_init *tab; 567 568 if (dev->dev_type == TM6010) { 569 tab = tm6010_init_tab; 570 size = ARRAY_SIZE(tm6010_init_tab); 571 } else { 572 tab = tm6000_init_tab; 573 size = ARRAY_SIZE(tm6000_init_tab); 574 } 575 576 /* Load board's initialization table */ 577 for (i = 0; i < size; i++) { 578 rc = tm6000_set_reg(dev, tab[i].req, tab[i].reg, tab[i].val); 579 if (rc < 0) { 580 printk(KERN_ERR "Error %i while setting req %d, " 581 "reg %d to value %d\n", rc, 582 tab[i].req, tab[i].reg, tab[i].val); 583 return rc; 584 } 585 } 586 587 msleep(5); /* Just to be conservative */ 588 589 /* Check board version - maybe 10Moons specific */ 590 board = tm6000_get_reg32(dev, REQ_40_GET_VERSION, 0, 0); 591 if (board >= 0) 592 printk(KERN_INFO "Board version = 0x%08x\n", board); 593 else 594 printk(KERN_ERR "Error %i while retrieving board version\n", board); 595 596 rc = tm6000_cards_setup(dev); 597 598 return rc; 599} 600 601int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate) 602{ 603 int val; 604 605 if (dev->dev_type == TM6010) { 606 val = tm6000_get_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, 0); 607 if (val < 0) 608 return val; 609 val = (val & 0xf0) | 0x1; /* 48 kHz, not muted */ 610 val = tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, val); 611 if (val < 0) 612 return val; 613 } 614 615 val = tm6000_get_reg(dev, REQ_07_SET_GET_AVREG, 0xeb, 0x0); 616 if (val < 0) 617 return val; 618 619 val &= 0x0f; /* Preserve the audio input control bits */ 620 switch (bitrate) { 621 case 44100: 622 val |= 0xd0; 623 dev->audio_bitrate = bitrate; 624 break; 625 case 48000: 626 val |= 0x60; 627 dev->audio_bitrate = bitrate; 628 break; 629 } 630 val = tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xeb, val); 631 632 return val; 633} 634EXPORT_SYMBOL_GPL(tm6000_set_audio_bitrate); 635 636static LIST_HEAD(tm6000_devlist); 637static DEFINE_MUTEX(tm6000_devlist_mutex); 638 639/* 640 * tm6000_realease_resource() 641 */ 642 643void tm6000_remove_from_devlist(struct tm6000_core *dev) 644{ 645 mutex_lock(&tm6000_devlist_mutex); 646 list_del(&dev->devlist); 647 mutex_unlock(&tm6000_devlist_mutex); 648}; 649 650void tm6000_add_into_devlist(struct tm6000_core *dev) 651{ 652 mutex_lock(&tm6000_devlist_mutex); 653 list_add_tail(&dev->devlist, &tm6000_devlist); 654 mutex_unlock(&tm6000_devlist_mutex); 655}; 656 657/* 658 * Extension interface 659 */ 660 661static LIST_HEAD(tm6000_extension_devlist); 662static DEFINE_MUTEX(tm6000_extension_devlist_lock); 663 664int tm6000_call_fillbuf(struct tm6000_core *dev, enum tm6000_ops_type type, 665 char *buf, int size) 666{ 667 struct tm6000_ops *ops = NULL; 668 669 670 if (!list_empty(&tm6000_extension_devlist)) { 671 list_for_each_entry(ops, &tm6000_extension_devlist, next) { 672 if (ops->fillbuf && ops->type == type) 673 ops->fillbuf(dev, buf, size); 674 } 675 } 676 677 return 0; 678} 679 680int tm6000_register_extension(struct tm6000_ops *ops) 681{ 682 struct tm6000_core *dev = NULL; 683 684 mutex_lock(&tm6000_devlist_mutex); 685 mutex_lock(&tm6000_extension_devlist_lock); 686 list_add_tail(&ops->next, &tm6000_extension_devlist); 687 list_for_each_entry(dev, &tm6000_devlist, devlist) { 688 ops->init(dev); 689 printk(KERN_INFO "%s: Initialized (%s) extension\n", 690 dev->name, ops->name); 691 } 692 mutex_unlock(&tm6000_extension_devlist_lock); 693 mutex_unlock(&tm6000_devlist_mutex); 694 return 0; 695} 696EXPORT_SYMBOL(tm6000_register_extension); 697 698void tm6000_unregister_extension(struct tm6000_ops *ops) 699{ 700 struct tm6000_core *dev = NULL; 701 702 mutex_lock(&tm6000_devlist_mutex); 703 list_for_each_entry(dev, &tm6000_devlist, devlist) { 704 if (dev) 705 ops->fini(dev); 706 } 707 708 mutex_lock(&tm6000_extension_devlist_lock); 709 printk(KERN_INFO "tm6000: Remove (%s) extension\n", ops->name); 710 list_del(&ops->next); 711 mutex_unlock(&tm6000_extension_devlist_lock); 712 mutex_unlock(&tm6000_devlist_mutex); 713} 714EXPORT_SYMBOL(tm6000_unregister_extension); 715 716void tm6000_init_extension(struct tm6000_core *dev) 717{ 718 struct tm6000_ops *ops = NULL; 719 720 mutex_lock(&tm6000_extension_devlist_lock); 721 if (!list_empty(&tm6000_extension_devlist)) { 722 list_for_each_entry(ops, &tm6000_extension_devlist, next) { 723 if (ops->init) 724 ops->init(dev); 725 } 726 } 727 mutex_unlock(&tm6000_extension_devlist_lock); 728} 729 730void tm6000_close_extension(struct tm6000_core *dev) 731{ 732 struct tm6000_ops *ops = NULL; 733 734 mutex_lock(&tm6000_extension_devlist_lock); 735 if (!list_empty(&tm6000_extension_devlist)) { 736 list_for_each_entry(ops, &tm6000_extension_devlist, next) { 737 if (ops->fini) 738 ops->fini(dev); 739 } 740 } 741 mutex_unlock(&tm6000_extension_devlist_lock); 742} 743