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 5162cd4..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 {
@@ -471,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 },
@@ -591,51 +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);
-               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(dev, TM6010_REQ08_R0A_A_I2S_MOD, areg_0a);
                if (val < 0)
                        return val;
-       }
 
-       /* different reg's to set audio bitrate */
-       if (dev->dev_type == TM6010) {
-               val = tm6000_get_reg(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
-                       0x0);
+               val = tm6000_set_reg_mask(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
+                                                       areg_f0, 0xf0);
                if (val < 0)
                        return val;
        } else {
-               val = tm6000_get_reg(dev, TM6000_REQ07_REB_VADC_AADC_MODE, 0x0);
+               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 &= 0x0f;            /* Preserve the audio input control bits */
-       switch (bitrate) {
-       case 44100:
-               val |= 0xd0;
-               dev->audio_bitrate = bitrate;
+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;
+
+               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;
        }
-       if (dev->dev_type == TM6010)
-               val = tm6000_set_reg(dev, TM6010_REQ08_RF0_DAUDIO_INPUT_CONFIG,
-                       val);
-       else
-               val = tm6000_set_reg(dev, TM6000_REQ07_REB_VADC_AADC_MODE, val);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(tm6000_tvaudio_set_mute);
+
+void tm6010_set_volume_sif(struct tm6000_core *dev, int vol)
+{
+       u8 vol_reg;
 
-       return val;
+       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);
 }
-EXPORT_SYMBOL_GPL(tm6000_set_audio_bitrate);
+
+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;
+
+       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_volume);
 
 static LIST_HEAD(tm6000_devlist);
 static DEFINE_MUTEX(tm6000_devlist_mutex);