summaryrefslogtreecommitdiff
path: root/drivers/staging/tm6000/tm6000-core.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/tm6000/tm6000-core.c')
-rw-r--r--drivers/staging/tm6000/tm6000-core.c298
1 files changed, 250 insertions, 48 deletions
diff --git a/drivers/staging/tm6000/tm6000-core.c b/drivers/staging/tm6000/tm6000-core.c
index 96aed4ace467..778e53413afb 100644
--- a/drivers/staging/tm6000/tm6000-core.c
+++ b/drivers/staging/tm6000/tm6000-core.c
@@ -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);