📄 ak470x.c
字号:
static int ak470x_switch_post_regbackbuffer (struct i2c_client *client){ return ak470x_write_block (client, ak470x_RegBackBuffer, is_ak4702 ? AK4702_NR_REG+1 : AK4706_NR_REG+1);}// ----------------------- AK470X Mode Function (Loopthrough) -----------------static void ak470x_switch_set_loopthrough (int loopthrough){ // Loopthrough Mode if (loopthrough) { ak470x_RegBackBuffer[AK470X_CONTROL] |= 0x01; } else { ak470x_RegBackBuffer[AK470X_CONTROL] &= ~0x01; }}// ----------------------- AK470X Mode Function (Global Switch Setup) --------int ak470x_switch_set (const av_switch_data* pInfo){ // Store settings av_current_info = *pInfo; // Loopthrough Mode ak470x_switch_set_loopthrough (pInfo->loopthrough); // // Reset all register values to zero // // - Preserve 'ak470x_RegBackBuffer[AK470X_VOLUME]' // - Preserve 'ak470x_RegBackBuffer[AK470X_ZEROCROSS]' // ak470x_RegBackBuffer[AK470X_START_REG] = 0x00; ak470x_RegBackBuffer[AK470X_MAIN_SWITCH] = 0x04; ak470x_RegBackBuffer[AK470X_VIDEO_SWITCH] = 0x00; ak470x_RegBackBuffer[AK470X_VIDEO_OUTPUT] = 0x00; ak470x_RegBackBuffer[AK470X_VIDEO_VOLUME] = 0x04; ak470x_RegBackBuffer[AK470X_BLANKING_CONTROL] = 0x00; ak470x_RegBackBuffer[AK470X_BLANKING_MONITOR] = 0x00; ak470x_RegBackBuffer[AK4706_MONITOR_MASK] = 0x08; ak470x_RegBackBuffer[AK4706_HD_SWITCH] = 0x00; ak470x_RegBackBuffer[AK4706_HD_FILTER] = 0x2A; // TV Output Source Select switch(pInfo->attribute[TV_OUTPUT].src_select) { case(SRC_PRIMARY) : switch(pInfo->attribute[TV_OUTPUT].display_mode) { case(MODE_RGB) : ak470x_RegBackBuffer[AK470X_VIDEO_SWITCH] |= 0x01; ak470x_RegBackBuffer[AK470X_BLANKING_CONTROL] |= 0x01; break; case(MODE_YC) : ak470x_RegBackBuffer[AK470X_VIDEO_SWITCH] |= 0x03; break; case(MODE_CVBS) : ak470x_RegBackBuffer[AK470X_VIDEO_SWITCH] |= 0x01; break; } break; case(SRC_SECONDARY) : switch(pInfo->attribute[TV_OUTPUT].display_mode) { case(MODE_RGB) : /* Invalid Mode */ dprintk(1, KERN_INFO "AK470X: SECONDARY output RGB mode not possible - Falling back to CVBS\n"); /* Fall through! */ case(MODE_CVBS) : ak470x_RegBackBuffer[AK470X_VIDEO_SWITCH] |= 0x02; break; case(MODE_YC) : ak470x_RegBackBuffer[AK470X_VIDEO_SWITCH] |= 0x02; break; } break; case(SRC_TVIN) : /* Invalid Mode */ dprintk(1, KERN_INFO "AK470X: TV OUT using TV IN src not possible\n"); return -EINVAL; break; case(SRC_VCRIN) : /* This mode is used during HD output ... do not route audio from VCR IN! */ // ak470x_RegBackBuffer[AK470X_MAIN_SWITCH] |= 0x01; ak470x_RegBackBuffer[AK470X_VIDEO_SWITCH] |= 0x04; break; case(SRC_MUTE) : ak470x_RegBackBuffer[AK470X_MAIN_SWITCH] |= 0x02; break; } // VCR Output Source Select switch(pInfo->attribute[VCR_OUTPUT].src_select) { case(SRC_PRIMARY) : switch(pInfo->attribute[VCR_OUTPUT].display_mode) { case(MODE_RGB) : /* Invalid Mode */ dprintk(1, KERN_INFO "AK470X: VCR RGB mode not possible - Falling back to CVBS\n"); /* Fall through! */ case(MODE_CVBS) : ak470x_RegBackBuffer[AK470X_VIDEO_SWITCH] |= 0x08; break; case(MODE_YC) : ak470x_RegBackBuffer[AK470X_VIDEO_SWITCH] |= 0x08; break; } break; case(SRC_SECONDARY) : /* Mute the audio output - if not using the primary output source */ ak470x_RegBackBuffer[AK470X_MAIN_SWITCH] |= 0x20; switch(pInfo->attribute[VCR_OUTPUT].display_mode) { case(MODE_RGB) : /* Invalid Mode */ dprintk(1, KERN_INFO "AK470X: VCR RGB mode not possible - Falling back to CVBS\n"); /* Fall through! */ case(MODE_CVBS) : ak470x_RegBackBuffer[AK470X_VIDEO_SWITCH] |= 0x10; break; case(MODE_YC) : ak470x_RegBackBuffer[AK470X_VIDEO_SWITCH] |= 0x10; break; } break; case(SRC_TVIN) : ak470x_RegBackBuffer[AK470X_MAIN_SWITCH] |= 0x10; ak470x_RegBackBuffer[AK470X_VIDEO_SWITCH] |= 0x18; break; case(SRC_VCRIN) : /* Invalid Mode */ dprintk(1, KERN_INFO "AK470X: VCR OUT using VCR IN src not possible\n"); return -EINVAL; break; case(SRC_MUTE) : ak470x_RegBackBuffer[AK470X_MAIN_SWITCH] |= 0x20; break; } // TV Output Display Mode Select switch(pInfo->attribute[TV_OUTPUT].display_mode) { case(MODE_RGB) : ak470x_RegBackBuffer[AK470X_VIDEO_OUTPUT] |= 0x4F; break; case(MODE_YC) : ak470x_RegBackBuffer[AK470X_VIDEO_OUTPUT] |= 0x03; break; case(MODE_CVBS) : ak470x_RegBackBuffer[AK470X_VIDEO_OUTPUT] |= 0x01; break; } // VCR Output Display Mode Select switch(pInfo->attribute[VCR_OUTPUT].display_mode) { case(MODE_RGB) : /* Invalid Mode */ dprintk(1, KERN_INFO "AK470X: VCR RGB mode not possible - Falling back to CVBS\n"); /* Fall through! */ case(MODE_CVBS) : ak470x_RegBackBuffer[AK470X_VIDEO_OUTPUT] |= 0x10; break; case(MODE_YC) : ak470x_RegBackBuffer[AK470X_VIDEO_OUTPUT] |= 0x30; break; } // Loopthrough Mode Fallback if (pInfo->loopthrough) { ak470x_RegBackBuffer[AK470X_BLANKING_CONTROL] |= 0xC0; } else { // TV Output Slow Blanking Select switch(pInfo->attribute[TV_OUTPUT].slow_blanking) { case(BLANK_SLOW_OFF) : break; case(BLANK_SLOW_16_9) : ak470x_RegBackBuffer[AK470X_BLANKING_CONTROL] |= 0x04; break; case(BLANK_SLOW_4_3) : ak470x_RegBackBuffer[AK470X_BLANKING_CONTROL] |= 0x0C; break; case(BLANK_SLOW_FOLLOW) : ak470x_RegBackBuffer[AK470X_BLANKING_CONTROL] |= 0xC0; break; case(BLANK_SLOW_MONITOR) : dprintk(1, KERN_INFO "AK470X: MONITOR of TV slow blanking not possible\n"); return -EINVAL; break; } // VCR Output Slow Blanking Select switch(pInfo->attribute[VCR_OUTPUT].slow_blanking) { case(BLANK_SLOW_OFF) : break; case(BLANK_SLOW_16_9) : ak470x_RegBackBuffer[AK470X_BLANKING_CONTROL] |= 0x10; break; case(BLANK_SLOW_4_3) : ak470x_RegBackBuffer[AK470X_BLANKING_CONTROL] |= 0x30; break; case(BLANK_SLOW_FOLLOW) : dprintk(1, KERN_INFO "AK470X: FOLLOW for VCR slow blanking not possible\n"); return -EINVAL; break; case(BLANK_SLOW_MONITOR) : ak470x_RegBackBuffer[AK470X_BLANKING_CONTROL] |= 0x80; break; } } return ak470x_switch_post_regbackbuffer (ak470x_client);}// ----------------------- AK470X Mode Get Function (Global Switch Read) ----int ak470x_switch_get (av_switch_data* pInfo){ *pInfo = av_current_info; return 0;}// ----------------------- AK470X function to determine if it is supported on this board or not. ----int ak470x_switch_installed (){ return ak470x_installed;}// ----------------------- AK470X Mode Function (Global init) ----------------static int ak470x_switch_init (struct i2c_client *client){ int i; for(i=0; i<AK4702_NR_REG+1; i++) ak470x_RegBackBuffer[i] = 0; // Default volume : 0dB ak470x_RegBackBuffer[AK470X_CONTROL] = 0x70; ak470x_RegBackBuffer[AK470X_VOLUME] = 0x1F; ak470x_RegBackBuffer[AK470X_ZEROCROSS] = 0x27; // Initialise the AV switch loop through mode av_def_info.loopthrough = loopthrough; return ak470x_switch_set (&av_def_info);}// ****************************************************************************// * *// * A U D I O S E C T I O N *// * *// ****************************************************************************//// ----------------------------------------------------------------------------// Misc Utilities// ----------------------------------------------------------------------------// ----------------------- Channel Number policy ----------------------------static inline int ak470x_audio_channel_number_isvalid (int channel){ return ((channel >= AK470X_AUDIO_CHANNEL_NUMBER_MIN) && (channel <= AK470X_AUDIO_CHANNEL_NUMBER_MAX));}// ----------------------- Channel Number to index --------------------------static inline int ak470x_audio_channel_number_to_index (int channel){ return (channel - AK470X_AUDIO_CHANNEL_NUMBER_MIN);}// ----------------------------------------------------------------------------// Volume norm conversion support// ----------------------------------------------------------------------------// ----------------------- AK470X associative volume buffer -------------------static AK470X_AUDIO_IOCTL_VOLUME_t ak470x_delta_volume [AK470X_AUDIO_CHANNEL_COUNT] = { [0 ... (AK470X_AUDIO_CHANNEL_COUNT-1)]= { .audio_channel = 0 , .master_left = AK470X_AUDIO_INTERNAL_GAIN_MIN , .master_right = AK470X_AUDIO_INTERNAL_GAIN_MIN , .external_left = AK470X_AUDIO_EXTERNAL_VOLUME_MIN , .external_right = AK470X_AUDIO_EXTERNAL_VOLUME_MIN }};// ----------------------- AK470X enforce strict boundaries policy ------------static inline int ak470x_enforce_volume_boundaries (int val, int min_val, int max_val){ return (val < min_val)? min_val : (val > max_val)? max_val : val;}// ----------------------- AK470X internal gain to volume conversion --------static inline int ak470x_standard_volume (AK470X_AUDIO_MASTER_VOLUME_t Gain){ int gain = ak470x_enforce_volume_boundaries ((int)Gain, AK470X_gain_min, AK470X_gain_max); return AK470X_vol_min + (((gain-AK470X_gain_min) * AK470X_vol_mag) / AK470X_gain_mag);}// ----------------------- AK470X volume to internal gain conversion --------static inline AK470X_AUDIO_MASTER_VOLUME_t ak470x_internal_gain (int Volume){ int volume = ak470x_enforce_volume_boundaries ((int)Volume, AK470X_vol_min, AK470X_vol_max); return (AK470X_AUDIO_MASTER_VOLUME_t) AK470X_gain_min + (((volume-AK470X_vol_min) * AK470X_gain_mag) / AK470X_vol_mag);}// ----------------------------------------------------------------------------// I2C Audio I/O support// ----------------------------------------------------------------------------// ----------------------- I2C Audio Support Function (Read ) ------------static inline int ak470x_audio_read (struct i2c_client *client, u8 addr, u8 *byte_ptr){ return ak470x_audio_block_read (client, addr, byte_ptr, 1);}// ----------------------- I2C Audio Support Function (Write ) ------------static inline int ak470x_audio_write (struct i2c_client *client, u8 addr, u8 *byte_ptr){ return ak470x_audio_block_write (client, addr, byte_ptr, 1);}// ----------------------------------------------------------------------------// Mode control functions// ----------------------------------------------------------------------------// ----------------------- AK470X Audio Function (Mode) --------------------static int ak470x_set_audio_mode(struct i2c_client *client, AK470X_AUDIO_IOCTL_MODE_t *mode){ int retValue = -EINVAL; AK470X_AUDIO_CHANNEL_NUMBER_t channel = mode->audio_channel; if (ak470x_audio_channel_number_isvalid(channel)) { retValue = -EINVAL; // NOT IMPLEMENTED YET if (retValue) { dprintk(1, KERN_INFO "ak470x.c: Failed to setup mode for audio channel %d (0x%X) (Unimplemented)\n", (int) channel, retValue); return retValue; } } return retValue;}// ----------------------------------------------------------------------------// Volume control functions// ----------------------------------------------------------------------------// ----------------------- AK470X Audio Function (Volume get) ------------static int ak470x_audio_volume_get (struct i2c_client *client, AK470X_AUDIO_IOCTL_VOLUME_t *volume){ AK470X_AUDIO_CHANNEL_NUMBER_t channel; int retValue = -EINVAL; u8 data_byte = 0; // Check channel number channel = volume->audio_channel; if (!ak470x_audio_channel_number_isvalid(channel)) return retValue; // I2C buffered I/O retValue = ak470x_audio_read (client, AK470X_ADDR_VOLUME, &data_byte); if (retValue) { dprintk(1, KERN_INFO "ak470x.c: Failed to get volume for audio channel %d (0x%X)\n", (int) channel, retValue); return retValue; } // Refresh back buffer ak470x_RegBackBuffer[AK470X_VOLUME] = data_byte; // GET Audio Master Volume (L/R) volume->master_left = ak470x_RegBackBuffer[AK470X_VOLUME]; volume->master_right = ak470x_RegBackBuffer[AK470X_VOLUME]; return retValue;}// ----------------------- AK470X Audio Function (Volume set) ------------
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -