Merge branch 'rmobile-latest' of git://git.kernel.org/pub/scm/linux/kernel/git/lethal...
[pandora-kernel.git] / drivers / staging / tm6000 / tm6000-core.c
index 96aed4a..778e534 100644 (file)
@@ -116,6 +116,29 @@ int tm6000_get_reg(struct tm6000_core *dev, u8 req, u16 value, u16 index)
 }
 EXPORT_SYMBOL_GPL(tm6000_get_reg);
 
+int tm6000_set_reg_mask(struct tm6000_core *dev, u8 req, u16 value,
+                                               u16 index, u16 mask)
+{
+       int rc;
+       u8 buf[1];
+       u8 new_index;
+
+       rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR, req,
+                                       value, index, buf, 1);
+
+       if (rc < 0)
+               return rc;
+
+       new_index = (buf[0] & ~mask) | (index & mask);
+
+       if (new_index == index)
+               return 0;
+
+       return tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR,
+                                     req, value, new_index, NULL, 0);
+}
+EXPORT_SYMBOL_GPL(tm6000_set_reg_mask);
+
 int tm6000_get_reg16(struct tm6000_core *dev, u8 req, u16 value, u16 index)
 {
        int rc;
@@ -245,17 +268,12 @@ int tm6000_init_analog_mode(struct tm6000_core *dev)
        struct v4l2_frequency f;
 
        if (dev->dev_type == TM6010) {
-               int val;
-
                /* Enable video */
-               val = tm6000_get_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, 0);
-               val |= 0x60;
-               tm6000_set_reg(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF, val);
-               val = tm6000_get_reg(dev,
-                       TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0);
-               val &= ~0x40;
-               tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, val);
 
+               tm6000_set_reg_mask(dev, TM6010_REQ07_RCC_ACTIVE_VIDEO_IF,
+                                                       0x60, 0x60);
+               tm6000_set_reg_mask(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE,
+                                                       0x00, 0x40);
                tm6000_set_reg(dev, TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc);
 
        } else {
@@ -268,11 +286,11 @@ int tm6000_init_analog_mode(struct tm6000_core *dev)
                        tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x80);
 
                tm6000_set_reg(dev, TM6010_REQ07_RC3_HSTART1, 0x88);
-               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0x23);
+               tm6000_set_reg(dev, TM6000_REQ07_RDA_CLK_SEL, 0x23);
                tm6000_set_reg(dev, TM6010_REQ07_RD1_ADDR_FOR_REQ1, 0xc0);
                tm6000_set_reg(dev, TM6010_REQ07_RD2_ADDR_FOR_REQ2, 0xd8);
                tm6000_set_reg(dev, TM6010_REQ07_RD6_ENDP_REQ1_REQ2, 0x06);
-               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT0, 0x1f);
+               tm6000_set_reg(dev, TM6000_REQ07_RDF_PWDOWN_ACLK, 0x1f);
 
                /* AP Software reset */
                tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x08);
@@ -284,8 +302,8 @@ int tm6000_init_analog_mode(struct tm6000_core *dev)
                tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x00);
 
                /* E3: Select input 0 - TV tuner */
-               tm6000_set_reg(dev, TM6010_REQ07_RE3_OUT_SEL1, 0x00);
-               tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xeb, 0x60);
+               tm6000_set_reg(dev, TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x00);
+               tm6000_set_reg(dev, TM6000_REQ07_REB_VADC_AADC_MODE, 0x60);
 
                /* This controls input */
                tm6000_set_reg(dev, REQ_03_SET_GET_MCU_PIN, TM6000_GPIO_2, 0x0);
@@ -344,21 +362,21 @@ int tm6000_init_digital_mode(struct tm6000_core *dev)
                tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x08);
                tm6000_set_reg(dev, TM6010_REQ07_RFF_SOFT_RESET, 0x00);
                tm6000_set_reg(dev, TM6010_REQ07_R3F_RESET, 0x01);
-               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT0, 0x08);
-               tm6000_set_reg(dev, TM6010_REQ07_RE2_OUT_SEL2, 0x0c);
-               tm6000_set_reg(dev, TM6010_REQ07_RE8_TYPESEL_MOS_I2S, 0xff);
-               tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0x00eb, 0xd8);
+               tm6000_set_reg(dev, TM6000_REQ07_RDF_PWDOWN_ACLK, 0x08);
+               tm6000_set_reg(dev, TM6000_REQ07_RE2_VADC_STATUS_CTL, 0x0c);
+               tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0xff);
+               tm6000_set_reg(dev, TM6000_REQ07_REB_VADC_AADC_MODE, 0xd8);
                tm6000_set_reg(dev, TM6010_REQ07_RC0_ACTIVE_VIDEO_SOURCE, 0x40);
                tm6000_set_reg(dev, TM6010_REQ07_RC1_TRESHOLD, 0xd0);
                tm6000_set_reg(dev, TM6010_REQ07_RC3_HSTART1, 0x09);
-               tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0x37);
+               tm6000_set_reg(dev, TM6000_REQ07_RDA_CLK_SEL, 0x37);
                tm6000_set_reg(dev, TM6010_REQ07_RD1_ADDR_FOR_REQ1, 0xd8);
                tm6000_set_reg(dev, TM6010_REQ07_RD2_ADDR_FOR_REQ2, 0xc0);
                tm6000_set_reg(dev, TM6010_REQ07_RD6_ENDP_REQ1_REQ2, 0x60);
 
-               tm6000_set_reg(dev, TM6010_REQ07_RE2_OUT_SEL2, 0x0c);
-               tm6000_set_reg(dev, TM6010_REQ07_RE8_TYPESEL_MOS_I2S, 0xff);
-               tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0x00eb, 0x08);
+               tm6000_set_reg(dev, TM6000_REQ07_RE2_VADC_STATUS_CTL, 0x0c);
+               tm6000_set_reg(dev, TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0xff);
+               tm6000_set_reg(dev, TM6000_REQ07_REB_VADC_AADC_MODE, 0x08);
                msleep(50);
 
                tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 0x0020, 0x00);
@@ -388,18 +406,19 @@ struct reg_init {
 /* The meaning of those initializations are unknown */
 struct reg_init tm6000_init_tab[] = {
        /* REG  VALUE */
-       { TM6010_REQ07_RD8_IR_PULSE_CNT0, 0x1f },
+       { TM6000_REQ07_RDF_PWDOWN_ACLK, 0x1f },
        { TM6010_REQ07_RFF_SOFT_RESET, 0x08 },
        { TM6010_REQ07_RFF_SOFT_RESET, 0x00 },
        { TM6010_REQ07_RD5_POWERSAVE, 0x4f },
-       { TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0x23 },
-       { TM6010_REQ07_RD8_IR_WAKEUP_ADD, 0x08 },
-       { TM6010_REQ07_RE2_OUT_SEL2, 0x00 },
-       { TM6010_REQ07_RE3_OUT_SEL1, 0x10 },
-       { TM6010_REQ07_RE5_REMOTE_WAKEUP, 0x00 },
-       { TM6010_REQ07_RE8_TYPESEL_MOS_I2S, 0x00 },
-       { REQ_07_SET_GET_AVREG,  0xeb, 0x64 },          /* 48000 bits/sample, external input */
-       { REQ_07_SET_GET_AVREG,  0xee, 0xc2 },
+       { TM6000_REQ07_RDA_CLK_SEL, 0x23 },
+       { TM6000_REQ07_RDB_OUT_SEL, 0x08 },
+       { TM6000_REQ07_RE2_VADC_STATUS_CTL, 0x00 },
+       { TM6000_REQ07_RE3_VADC_INP_LPF_SEL1, 0x10 },
+       { TM6000_REQ07_RE5_VADC_INP_LPF_SEL2, 0x00 },
+       { TM6000_REQ07_RE8_VADC_PWDOWN_CTL, 0x00 },
+       { TM6000_REQ07_REB_VADC_AADC_MODE, 0x64 },      /* 48000 bits/sample, external input */
+       { TM6000_REQ07_REE_VADC_CTRL_SEL_CONTROL, 0xc2 },
+
        { TM6010_REQ07_R3F_RESET, 0x01 },               /* Start of soft reset */
        { TM6010_REQ07_R00_VIDEO_CONTROL0, 0x00 },
        { TM6010_REQ07_R01_VIDEO_CONTROL1, 0x07 },
@@ -470,6 +489,14 @@ struct reg_init tm6010_init_tab[] = {
        { TM6010_REQ08_REB_SIF_GAIN_CTRL, 0xf0 },
        { TM6010_REQ08_REC_REVERSE_YC_CTRL, 0xc2 },
        { TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG, 0x60 },
+       { TM6010_REQ08_R03_A_AUTO_GAIN_CTRL, 0x00},
+       { TM6010_REQ08_R04_A_SIF_AMP_CTRL, 0x80},
+       { TM6010_REQ08_R0C_A_ASD_THRES2, 0x0a},
+       { TM6010_REQ08_R0D_A_AMD_THRES, 0x40},
+       { TM6010_REQ08_R1A_A_NICAM_SER_MAX, 0x64},
+       { TM6010_REQ08_R1B_A_NICAM_SER_MIN, 0x20},
+       { TM6010_REQ08_R16_A_AGC_GAIN_MAX, 0xfe},
+       { TM6010_REQ08_R17_A_AGC_GAIN_MIN, 0x01},
        { TM6010_REQ08_RF1_AADC_POWER_DOWN, 0xfc },
 
        { TM6010_REQ07_R3F_RESET, 0x01 },
@@ -590,38 +617,213 @@ int tm6000_init(struct tm6000_core *dev)
 
 int tm6000_set_audio_bitrate(struct tm6000_core *dev, int bitrate)
 {
-       int val;
+       int val = 0;
+       u8 areg_f0 = 0x60; /* ADC MCLK = 250 Fs */
+       u8 areg_0a = 0x91; /* SIF 48KHz */
 
+       switch (bitrate) {
+       case 48000:
+               areg_f0 = 0x60; /* ADC MCLK = 250 Fs */
+               areg_0a = 0x91; /* SIF 48KHz */
+               dev->audio_bitrate = bitrate;
+               break;
+       case 32000:
+               areg_f0 = 0x00; /* ADC MCLK = 375 Fs */
+               areg_0a = 0x90; /* SIF 32KHz */
+               dev->audio_bitrate = bitrate;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+
+       /* enable I2S, if we use sif or external I2S device */
        if (dev->dev_type == TM6010) {
-               val = tm6000_get_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, 0);
+               val = tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, areg_0a);
                if (val < 0)
                        return val;
-               val = (val & 0xf0) | 0x1; /* 48 kHz, not muted */
-               val = tm6000_set_reg(dev, TM6010_REQ08_R0A_A_I2S_MOD, val);
+
+               val = tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
+                                                       areg_f0, 0xf0);
+               if (val < 0)
+                       return val;
+       } else {
+               val = tm6000_set_reg_mask(dev, TM6000_REQ07_REB_VADC_AADC_MODE,
+                                                       areg_f0, 0xf0);
                if (val < 0)
                        return val;
        }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(tm6000_set_audio_bitrate);
 
-       val = tm6000_get_reg(dev, REQ_07_SET_GET_AVREG, 0xeb, 0x0);
-       if (val < 0)
-               return val;
+int tm6000_set_audio_input(struct tm6000_core *dev, enum tm6000_inaudio ainp)
+{
+       if (dev->dev_type == TM6010) {
+               /* Audio crossbar setting, default SIF1 */
+               u8 areg_f0 = 0x03;
 
-       val &= 0x0f;            /* Preserve the audio input control bits */
-       switch (bitrate) {
-       case 44100:
-               val |= 0xd0;
-               dev->audio_bitrate = bitrate;
+               switch (ainp) {
+               case TM6000_AIP_SIF1:
+               case TM6000_AIP_SIF2:
+                       areg_f0 = 0x03;
+                       break;
+               case TM6000_AIP_LINE1:
+                       areg_f0 = 0x00;
+                       break;
+               case TM6000_AIP_LINE2:
+                       areg_f0 = 0x08;
+                       break;
+               default:
+                       return 0;
+                       break;
+               }
+               /* Set audio input crossbar */
+               tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
+                                                       areg_f0, 0x0f);
+       } else {
+               /* Audio setting, default LINE1 */
+               u8 areg_eb = 0x00;
+
+               switch (ainp) {
+               case TM6000_AIP_LINE1:
+                       areg_eb = 0x00;
+                       break;
+               case TM6000_AIP_LINE2:
+                       areg_eb = 0x04;
+                       break;
+               default:
+                       return 0;
+                       break;
+               }
+               /* Set audio input */
+               tm6000_set_reg_mask(dev, TM6000_REQ07_REB_VADC_AADC_MODE,
+                                                       areg_eb, 0x0f);
+       }
+       return 0;
+}
+EXPORT_SYMBOL_GPL(tm6000_set_audio_input);
+
+void tm6010_set_mute_sif(struct tm6000_core *dev, u8 mute)
+{
+       u8 mute_reg = 0;
+
+       if (mute)
+               mute_reg = 0x08;
+
+       tm6000_set_reg_mask(dev, TM6010_REQ08_R0A_A_I2S_MOD, mute_reg, 0x08);
+}
+
+void tm6010_set_mute_adc(struct tm6000_core *dev, u8 mute)
+{
+       u8 mute_reg = 0;
+
+       if (mute)
+               mute_reg = 0x20;
+
+       if (dev->dev_type == TM6010) {
+               tm6000_set_reg_mask(dev, TM6010_REQ08_RF2_LEFT_CHANNEL_VOL,
+                                                       mute_reg, 0x20);
+               tm6000_set_reg_mask(dev, TM6010_REQ08_RF3_RIGHT_CHANNEL_VOL,
+                                                       mute_reg, 0x20);
+       } else {
+               tm6000_set_reg_mask(dev, TM6000_REQ07_REC_VADC_AADC_LVOL,
+                                                       mute_reg, 0x20);
+               tm6000_set_reg_mask(dev, TM6000_REQ07_RED_VADC_AADC_RVOL,
+                                                       mute_reg, 0x20);
+       }
+}
+
+int tm6000_tvaudio_set_mute(struct tm6000_core *dev, u8 mute)
+{
+       enum tm6000_inaudio ainp;
+
+       if (dev->radio)
+               ainp = dev->aradio;
+       else
+               ainp = dev->avideo;
+
+       switch (ainp) {
+       case TM6000_AIP_SIF1:
+       case TM6000_AIP_SIF2:
+               if (dev->dev_type == TM6010)
+                       tm6010_set_mute_sif(dev, mute);
+               else {
+                       printk(KERN_INFO "ERROR: TM5600 and TM6000 don't has"
+                                       " SIF audio inputs. Please check the %s"
+                                       " configuration.\n", dev->name);
+                       return -EINVAL;
+               }
                break;
-       case 48000:
-               val |= 0x60;
-               dev->audio_bitrate = bitrate;
+       case TM6000_AIP_LINE1:
+       case TM6000_AIP_LINE2:
+               tm6010_set_mute_adc(dev, mute);
+               break;
+       default:
+               return -EINVAL;
                break;
        }
-       val = tm6000_set_reg(dev, REQ_07_SET_GET_AVREG, 0xeb, val);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(tm6000_tvaudio_set_mute);
+
+void tm6010_set_volume_sif(struct tm6000_core *dev, int vol)
+{
+       u8 vol_reg;
+
+       vol_reg = vol & 0x0F;
+
+       if (vol < 0)
+               vol_reg |= 0x40;
+
+       tm6000_set_reg(dev, TM6010_REQ08_R07_A_LEFT_VOL, vol_reg);
+       tm6000_set_reg(dev, TM6010_REQ08_R08_A_RIGHT_VOL, vol_reg);
+}
+
+void tm6010_set_volume_adc(struct tm6000_core *dev, int vol)
+{
+       u8 vol_reg;
+
+       vol_reg = (vol + 0x10) & 0x1f;
+
+       if (dev->dev_type == TM6010) {
+               tm6000_set_reg(dev, TM6010_REQ08_RF2_LEFT_CHANNEL_VOL, vol_reg);
+               tm6000_set_reg(dev, TM6010_REQ08_RF3_RIGHT_CHANNEL_VOL, vol_reg);
+       } else {
+               tm6000_set_reg(dev, TM6000_REQ07_REC_VADC_AADC_LVOL, vol_reg);
+               tm6000_set_reg(dev, TM6000_REQ07_RED_VADC_AADC_RVOL, vol_reg);
+       }
+}
+
+void tm6000_set_volume(struct tm6000_core *dev, int vol)
+{
+       enum tm6000_inaudio ainp;
+
+       if (dev->radio) {
+               ainp = dev->aradio;
+               vol += 8; /* Offset to 0 dB */
+       } else
+               ainp = dev->avideo;
 
-       return val;
+       switch (ainp) {
+       case TM6000_AIP_SIF1:
+       case TM6000_AIP_SIF2:
+               if (dev->dev_type == TM6010)
+                       tm6010_set_volume_sif(dev, vol);
+               else
+                       printk(KERN_INFO "ERROR: TM5600 and TM6000 don't has"
+                                       " SIF audio inputs. Please check the %s"
+                                       " configuration.\n", dev->name);
+               break;
+       case TM6000_AIP_LINE1:
+       case TM6000_AIP_LINE2:
+               tm6010_set_volume_adc(dev, vol);
+               break;
+       default:
+               break;
+       }
 }
-EXPORT_SYMBOL_GPL(tm6000_set_audio_bitrate);
+EXPORT_SYMBOL_GPL(tm6000_set_volume);
 
 static LIST_HEAD(tm6000_devlist);
 static DEFINE_MUTEX(tm6000_devlist_mutex);