| /* |
| * Copyright (C) ST-Ericsson AB 2010 |
| * |
| * AV8100 driver |
| * |
| * Author: Per Persson <per.xb.persson@stericsson.com> |
| * for ST-Ericsson. |
| * |
| * License terms: GNU General Public License (GPL), version 2. |
| */ |
| |
| |
| #include <linux/kernel.h> |
| #include <linux/module.h> |
| #include <linux/device.h> |
| #include <linux/miscdevice.h> |
| #include <linux/platform_device.h> |
| #include <linux/i2c.h> |
| #include <linux/fs.h> |
| #include <linux/gpio.h> |
| #include <linux/delay.h> |
| #include <linux/kthread.h> |
| #include <linux/interrupt.h> |
| #include <linux/irq.h> |
| #include <linux/timer.h> |
| #include <linux/mutex.h> |
| |
| #include "av8100_regs.h" |
| #include <video/av8100.h> |
| #include <video/hdmi.h> |
| #include "av8100_fw.h" |
| #include "av8100v2_fw.h" |
| |
| #define AV8100_INT_EVENT 0x1 |
| #define AV8100_TIMER_INT_EVENT 0x2 |
| |
| #define AV8100_TIMER_INTERRUPT_POLLING_TIME 250 |
| |
| #define GPIO_AV8100_RSTN 196 |
| #define AV8100_MASTER_CLOCK_TIMING 0x3 |
| #define AV8100_ON_TIME 1 |
| #define AV8100_DENC_OFF_TIME 3 |
| #define AV8100_HDMI_OFF_TIME 0 |
| #define AV8100_COMMAND_OFFSET 0x10 |
| #define AV8100_COMMAND_MAX_LENGTH 0x81 |
| |
| #define AV8100_TE_LINE_NB_14 14 |
| #define AV8100_TE_LINE_NB_17 17 |
| #define AV8100_TE_LINE_NB_18 18 |
| #define AV8100_TE_LINE_NB_21 21 |
| #define AV8100_TE_LINE_NB_22 22 |
| #define AV8100_TE_LINE_NB_30 30 |
| #define AV8100_TE_LINE_NB_38 38 |
| #define AV8100_TE_LINE_NB_40 40 |
| #define AV8100_UI_X4_DEFAULT 6 |
| |
| #define HDMI_REQUEST_FOR_REVOCATION_LIST_INPUT 2 |
| #define HDMI_CEC_MESSAGE_WRITE_BUFFER_SIZE 16 |
| #define HDMI_HDCP_SEND_KEY_SIZE 7 |
| #define HDMI_INFOFRAME_DATA_SIZE 28 |
| #define HDMI_FUSE_AES_KEY_SIZE 16 |
| |
| #define HPDS_INVALID 0xF |
| #define CPDS_INVALID 0xF |
| #define CECRX_INVALID 0xF |
| |
| #define REG_16_8_LSB(p) ((u8)(p & 0xFF)) |
| #define REG_16_8_MSB(p) ((u8)((p & 0xFF00)>>8)) |
| #define REG_32_8_MSB(p) ((u8)((p & 0xFF000000)>>24)) |
| #define REG_32_8_MMSB(p) ((u8)((p & 0x00FF0000)>>16)) |
| #define REG_32_8_MLSB(p) ((u8)((p & 0x0000FF00)>>8)) |
| #define REG_32_8_LSB(p) ((u8)(p & 0x000000FF)) |
| #define REG_10_8_MSB(p) ((u8)((p & 0x300)>>8)) |
| #define REG_12_8_MSB(p) ((u8)((p & 0xf00)>>8)) |
| |
| DEFINE_MUTEX(av8100_hw_mutex); |
| #define LOCK_AV8100_HW mutex_lock(&av8100_hw_mutex) |
| #define UNLOCK_AV8100_HW mutex_unlock(&av8100_hw_mutex) |
| |
| #define AV8100_DEBUG_EXTRA |
| #define AV8100_PLUGIN_DETECT_VIA_TIMER_INTERRUPTS |
| #define CEC_ADDR_OFFSET 3 |
| |
| struct av8100_config_t { |
| struct i2c_client *client; |
| struct i2c_device_id *id; |
| struct av8100_video_input_format_cmd hdmi_video_input_cmd; |
| struct av8100_audio_input_format_cmd hdmi_audio_input_cmd; |
| struct av8100_video_output_format_cmd hdmi_video_output_cmd; |
| struct av8100_video_scaling_format_cmd hdmi_video_scaling_cmd; |
| struct av8100_color_space_conversion_format_cmd |
| hdmi_color_space_conversion_cmd; |
| struct av8100_cec_message_write_format_cmd |
| hdmi_cec_message_write_cmd; |
| struct av8100_cec_message_read_back_format_cmd |
| hdmi_cec_message_read_back_cmd; |
| struct av8100_denc_format_cmd hdmi_denc_cmd; |
| struct av8100_hdmi_cmd hdmi_cmd; |
| struct av8100_hdcp_send_key_format_cmd hdmi_hdcp_send_key_cmd; |
| struct av8100_hdcp_management_format_cmd |
| hdmi_hdcp_management_format_cmd; |
| struct av8100_infoframes_format_cmd hdmi_infoframes_cmd; |
| struct av8100_edid_section_readback_format_cmd |
| hdmi_edid_section_readback_cmd; |
| struct av8100_pattern_generator_format_cmd hdmi_pattern_generator_cmd; |
| struct av8100_fuse_aes_key_format_cmd hdmi_fuse_aes_key_cmd; |
| }; |
| |
| struct av8100_globals_t { |
| int denc_off_time;/* 5 volt time */ |
| int hdmi_off_time;/* 5 volt time */ |
| int on_time;/* 5 volt time */ |
| u8 hpdm;/*stby_int_mask*/ |
| u8 cpdm;/*stby_int_mask*/ |
| #ifdef AV8100_PLUGIN_DETECT_VIA_TIMER_INTERRUPTS |
| u8 hpds_old; |
| u8 cpds_old; |
| u8 cecrx_old; |
| u8 hdcps_old; |
| #endif |
| void (*hdmi_ev_cb)(enum av8100_hdmi_event); |
| }; |
| |
| /** |
| * struct av8100_cea - CEA(consumer electronic access) standard structure |
| * @cea_id: |
| * @cea_nb: |
| * @vtotale: |
| **/ |
| |
| struct av8100_cea { |
| char cea_id[40]; |
| int cea_nb; |
| int vtotale; |
| int vactive; |
| int vsbp; |
| int vslen; |
| int vsfp; |
| char vpol[5]; |
| int htotale; |
| int hactive; |
| int hbp; |
| int hslen; |
| int hfp; |
| int frequence; |
| char hpol[5]; |
| int reg_line_duration; |
| int blkoel_duration; |
| int uix4; |
| int pll_mult; |
| int pll_div; |
| }; |
| |
| enum av8100_command_size { |
| AV8100_COMMAND_VIDEO_INPUT_FORMAT_SIZE = 0x17, |
| AV8100_COMMAND_AUDIO_INPUT_FORMAT_SIZE = 0x8, |
| AV8100_COMMAND_VIDEO_OUTPUT_FORMAT_SIZE = 0x1E, |
| AV8100_COMMAND_VIDEO_SCALING_FORMAT_SIZE = 0x11, |
| AV8100_COMMAND_COLORSPACECONVERSION_SIZE = 0x1D, |
| AV8100_COMMAND_CEC_MESSAGE_WRITE_SIZE = 0x12, |
| AV8100_COMMAND_CEC_MESSAGE_READ_BACK_SIZE = 0x1, |
| AV8100_COMMAND_DENC_SIZE = 0x6, |
| AV8100_COMMAND_HDMI_SIZE = 0x4, |
| AV8100_COMMAND_HDCP_SENDKEY_SIZE = 0xA, |
| AV8100_COMMAND_HDCP_MANAGEMENT_SIZE = 0x4, |
| AV8100_COMMAND_INFOFRAMES_SIZE = 0x21, |
| AV8100_COMMAND_EDID_SECTION_READBACK_SIZE = 0x3, |
| AV8100_COMMAND_PATTERNGENERATOR_SIZE = 0x4, |
| AV8100_COMMAND_FUSE_AES_KEY_SIZE = 0x12, |
| }; |
| |
| static void clr_plug_status(enum av8100_plugin_status status); |
| static void set_plug_status(enum av8100_plugin_status status); |
| static void cec_rx(void); |
| static void hdcp_changed(void); |
| static int av8100_open(struct inode *inode, struct file *filp); |
| static int av8100_release(struct inode *inode, struct file *filp); |
| static int av8100_ioctl(struct inode *inode, struct file *file, |
| unsigned int cmd, unsigned long arg); |
| static int __devinit av8100_probe(struct i2c_client *i2cClient, |
| const struct i2c_device_id *id); |
| static int __devexit av8100_remove(struct i2c_client *i2cClient); |
| |
| static struct av8100_config_t *av8100_config; |
| static struct av8100_status g_av8100_status = {0}; |
| #ifdef AV8100_PLUGIN_DETECT_VIA_TIMER_INTERRUPTS |
| static struct timer_list av8100_timer; |
| #endif |
| static wait_queue_head_t av8100_event; |
| static int av8100_flag = 0x0; |
| static struct av8100_globals_t *av8100_globals; |
| static u8 chip_version; |
| static char av8100_receivetab[AV8100_FW_SIZE_V2]; |
| struct device *av8100dev; |
| |
| static const struct file_operations av8100_fops = { |
| .owner = THIS_MODULE, |
| .open = av8100_open, |
| .release = av8100_release, |
| .ioctl = av8100_ioctl |
| }; |
| |
| static struct miscdevice av8100_miscdev = { |
| MISC_DYNAMIC_MINOR, |
| "av8100", |
| &av8100_fops |
| }; |
| |
| struct av8100_cea av8100_all_cea[29] = { |
| /* cea id |
| * cea_nr vtot vact vsbpp vslen |
| * vsfp vpol htot hact hbp hslen hfp freq |
| * hpol rld bd uix4 pm pd */ |
| { "0 CUSTOM ", |
| 0, 0, 0, 0, 0, |
| 0, "-", 800, 640, 16, 96, 10, 25200000, |
| "-", 0, 0, 0, 0, 0},/*Settings to be defined*/ |
| { "1 CEA 1 VESA 4 640x480p @ 60 Hz ", |
| 1, 525, 480, 33, 2, |
| 10, "-", 800, 640, 49, 290, 146, 25200000, |
| "-", 2438, 1270, 6, 32, 1},/*RGB888*/ |
| { "2 CEA 2 - 3 720x480p @ 60 Hz 4:3 ", |
| 2, 525, 480, 30, 6, |
| 9, "-", 858, 720, 34, 130, 128, 27027000, |
| "-", 1828, 0x3C0, 8, 24, 1},/*RGB565*/ |
| { "3 CEA 4 1280x720p @ 60 Hz ", |
| 4, 750, 720, 20, 5, |
| 5, "+", 1650, 1280, 114, 39, 228, 74250000, |
| "+", 1706, 164, 6, 32, 1},/*RGB565*/ |
| { "4 CEA 5 1920x1080i @ 60 Hz ", |
| 5, 1125, 540, 20, 5, |
| 0, "+", 2200, 1920, 88, 44, 10, 74250000, |
| "+", 0, 0, 0, 0, 0},/*Settings to be define*/ |
| { "5 CEA 6-7 480i (NTSC) ", |
| 6, 525, 240, 44, 5, |
| 0, "-", 858, 720, 12, 64, 10, 13513513, |
| "-", 0, 0, 0, 0, 0},/*Settings to be define*/ |
| { "6 CEA 14-15 480p @ 60 Hz ", |
| 14, 525, 480, 44, 5, |
| 0, "-", 858, 720, 12, 64, 10, 27027000, |
| "-", 0, 0, 0, 0, 0},/*Settings to be define*/ |
| { "7 CEA 16 1920x1080p @ 60 Hz ", |
| 16, 1125, 1080, 36, 5, |
| 0, "+", 1980, 1280, 440, 40, 10, 133650000, |
| "+", 0, 0, 0, 0, 0},/*Settings to be define*/ |
| { "8 CEA 17-18 720x576p @ 50 Hz ", |
| 17, 625, 576, 44, 5, |
| 0, "-", 864, 720, 12, 64, 10, 27000000, |
| "-", 0, 0, 0, 0, 0},/*Settings to be define*/ |
| { "9 CEA 19 1280x720p @ 50 Hz ", |
| 19, 750, 720, 25, 5, |
| 0, "+", 1980, 1280, 440, 40, 10, 74250000, |
| "+", 0, 0, 0, 0, 0},/*Settings to be define*/ |
| { "10 CEA 20 1920 x 1080i @ 50 Hz ", |
| 20, 1125, 540, 20, 5, |
| 0, "+", 2640, 1920, 528, 44, 10, 74250000, |
| "+", 0, 0, 0, 0, 0},/*Settings to be define*/ |
| { "11 CEA 21-22 576i (PAL) ", |
| 21, 625, 288, 44, 5, |
| 0, "-", 1728, 1440, 12, 64, 10, 27000000, |
| "-", 0, 0, 0, 0, 0},/*Settings to be define*/ |
| { "12 CEA 29/30 576p ", |
| 29, 625, 576, 44, 5, |
| 0, "-", 864, 720, 12, 64, 10, 27000000, |
| "-", 0, 0, 0, 0, 0},/*Settings to be define*/ |
| { "13 CEA 31 1080p 50Hz ", |
| 31, 1125, 1080, 44, 5, |
| 0, "-", 2640, 1920, 12, 64, 10, 148500000, |
| "-", 0, 0, 0, 0, 0},/*Settings to be define*/ |
| { "14 CEA 32 1920x1080p @ 24 Hz ", |
| 32, 1125, 1080, 36, 5, |
| 4, "+", 2750, 1920, 660, 44, 153, 74250000, |
| "+", 2844, 0x530, 6, 32, 1},/*RGB565*/ |
| { "15 CEA 33 1920x1080p @ 25 Hz ", |
| 33, 1125, 1080, 36, 5, |
| 4, "+", 2640, 1920, 528, 44, 10, 74250000, |
| "+", 0, 0, 0, 0, 0},/*Settings to be define*/ |
| { "16 CEA 34 1920x1080p @ 30Hz ", |
| 34, 1125, 1080, 36, 5, |
| 4, "+", 2200, 1920, 91, 44, 153, 74250000, |
| "+", 2275, 0xAB, 6, 32, 1},/*RGB565*/ |
| { "17 CEA 60 1280x720p @ 24 Hz ", |
| 60, 750, 720, 20, 5, |
| 5, "+", 3300, 1280, 284, 50, 2276, 59400000, |
| "+", 4266, 0xAD0, 5, 32, 1},/*RGB565*/ |
| { "18 CEA 61 1280x720p @ 25 Hz ", |
| 61, 750, 720, 20, 5, |
| 5, "+", 3960, 1280, 228, 39, 2503, 74250000, |
| "+", 4096, 0x500, 5, 32, 1},/*RGB565*/ |
| { "19 CEA 62 1280x720p @ 30 Hz ", |
| 62, 750, 720, 20, 5, |
| 5, "+", 3300, 1280, 228, 39, 1820, 74250000, |
| "+", 3413, 0x770, 5, 32, 1},/*RGB565*/ |
| { "20 VESA 9 800x600 @ 60 Hz ", |
| 109, 628, 600, 28, 4, |
| 0, "+", 1056, 800, 40, 128, 10, 20782080, |
| "+", 0, 0, 0, 0, 0},/*Settings to be define*/ |
| { "21 VESA 14 848x480 @ 60 Hz ", |
| 114, 500, 480, 20, 5, |
| 0, "+", 1056, 848, 24, 80, 10, 31680000, |
| "-", 0, 0, 0, 0, 0},/*Settings to be define*/ |
| { "22 VESA 16 1024x768 @ 60 Hz ", |
| 116, 806, 768, 38, 6, |
| 0, "-", 1344, 1024, 24, 135, 10, 65000000, |
| "-", 0, 0, 0, 0, 0},/*Settings to be define*/ |
| { "23 VESA 22 1280x768 @ 60 Hz ", |
| 122, 802, 768, 34, 4, |
| 0, "+", 1688, 1280, 48, 160, 10, 81250000, |
| "-", 0, 0, 0, 0, 0},/*Settings to be define*/ |
| { "24 VESA 23 1280x768 @ 60 Hz ", |
| 123, 798, 768, 30, 7, |
| 0, "+", 1664, 1280, 64, 128, 10, 79500000, |
| "-", 0, 0, 0, 0, 0},/*Settings to be define*/ |
| { "25 VESA 27 1280x800 @ 60 Hz ", |
| 127, 823, 800, 23, 6, |
| 0, "+", 1440, 1280, 48, 32, 10, 71000000, |
| "+", 0, 0, 0, 0, 0},/*Settings to be define*/ |
| { "26 VESA 28 1280x800 @ 60 Hz ", |
| 128, 831, 800, 31, 6, |
| 0, "+", 1680, 1280, 72, 128, 10, 83500000, |
| "-", 0, 0, 0, 0, 0},/*Settings to be define*/ |
| { "27 VESA 39 1360x768 @ 60 Hz ", |
| 139, 790, 768, 22, 5, |
| 0, "-", 1520, 1360, 48, 32, 10, 72000000, |
| "+", 0, 0, 0, 0, 0},/*Settings to be define*/ |
| { "28 VESA 81 1360x768 @ 60 Hz ", |
| 181, 798, 768, 30, 5, |
| 0, "+", 1776, 1360, 72, 136, 10, 84750000, |
| "-", 0, 0, 0, 0, 0} /*Settings to be define*/ |
| }; |
| |
| const struct av8100_color_space_conversion_format_cmd col_cvt_identity = { |
| .c0 = 0x0100, |
| .c1 = 0x0000, |
| .c2 = 0x0000, |
| .c3 = 0x0000, |
| .c4 = 0x0100, |
| .c5 = 0x0000, |
| .c6 = 0x0000, |
| .c7 = 0x0000, |
| .c8 = 0x0100, |
| .aoffset = 0x0000, |
| .boffset = 0x0000, |
| .coffset = 0x0000, |
| .lmax = 0xff, |
| .lmin = 0x00, |
| .cmax = 0xff, |
| .cmin = 0x00, |
| }; |
| |
| const struct av8100_color_space_conversion_format_cmd |
| col_cvt_identity_clamp_yuv = { |
| .c0 = 0x0100, |
| .c1 = 0x0000, |
| .c2 = 0x0000, |
| .c3 = 0x0000, |
| .c4 = 0x0100, |
| .c5 = 0x0000, |
| .c6 = 0x0000, |
| .c7 = 0x0000, |
| .c8 = 0x0100, |
| .aoffset = 0x0000, |
| .boffset = 0x0000, |
| .coffset = 0x0000, |
| .lmax = 0xeb, |
| .lmin = 0x10, |
| .cmax = 0xf0, |
| .cmin = 0x10, |
| }; |
| |
| const struct av8100_color_space_conversion_format_cmd col_cvt_yuv422_to_rgb = { |
| .c0 = 0x00ba, |
| .c1 = 0x007d, |
| .c2 = 0x0000, |
| .c3 = 0xffa1, |
| .c4 = 0x007d, |
| .c5 = 0xffd3, |
| .c6 = 0x0000, |
| .c7 = 0x007d, |
| .c8 = 0x00eb, |
| .aoffset = 0xff9b, |
| .boffset = 0x003e, |
| .coffset = 0xff82, |
| .lmax = 0xff, |
| .lmin = 0x00, |
| .cmax = 0xff, |
| .cmin = 0x00, |
| }; |
| |
| const struct av8100_color_space_conversion_format_cmd col_cvt_yuv422_to_denc = { |
| .c0 = 0x0000, |
| .c1 = 0x0000, |
| .c2 = 0x0100, |
| .c3 = 0x0000, |
| .c4 = 0x0100, |
| .c5 = 0x0000, |
| .c6 = 0x0100, |
| .c7 = 0x0000, |
| .c8 = 0x0000, |
| .aoffset = 0x0000, |
| .boffset = 0x0000, |
| .coffset = 0x0000, |
| .lmax = 0xeb, |
| .lmin = 0x10, |
| .cmax = 0xf0, |
| .cmin = 0x10, |
| }; |
| |
| const struct av8100_color_space_conversion_format_cmd col_cvt_rgb_to_denc = { |
| .c0 = 0xffda, |
| .c1 = 0xffb6, |
| .c2 = 0x0070, |
| .c3 = 0x0042, |
| .c4 = 0x0081, |
| .c5 = 0x0019, |
| .c6 = 0x0070, |
| .c7 = 0xffa2, |
| .c8 = 0xffee, |
| .aoffset = 0x007f, |
| .boffset = 0x0010, |
| .coffset = 0x007f, |
| .lmax = 0xff, |
| .lmin = 0x00, |
| .cmax = 0xff, |
| .cmin = 0x00, |
| }; |
| |
| static const struct i2c_device_id av8100_id[] = { |
| { "av8100", 0 }, |
| { } |
| }; |
| |
| static struct i2c_driver av8100_driver = { |
| .probe = av8100_probe, |
| .remove = av8100_remove, |
| .driver = { |
| .name = "av8100", |
| }, |
| .id_table = av8100_id, |
| }; |
| |
| #ifdef AV8100_PLUGIN_DETECT_VIA_TIMER_INTERRUPTS |
| static void av8100_timer_int(unsigned long value) |
| { |
| av8100_flag |= AV8100_TIMER_INT_EVENT; |
| wake_up_interruptible(&av8100_event); |
| |
| if (g_av8100_status.av8100_state >= AV8100_OPMODE_STANDBY) { |
| av8100_timer.expires = jiffies + |
| AV8100_TIMER_INTERRUPT_POLLING_TIME; |
| add_timer(&av8100_timer); |
| } |
| } |
| #endif |
| |
| static int av8100_thread(void *p) |
| { |
| u8 hpds = 0; |
| u8 cpds = 0; |
| u8 hdcps = 0; |
| int ret = 0; |
| #ifdef AV8100_PLUGIN_DETECT_VIA_TIMER_INTERRUPTS |
| u8 cecrx; |
| u8 *hpds_old; |
| u8 *cpds_old; |
| u8 *cecrx_old; |
| u8 *hdcps_old; |
| #else |
| u8 sid = 0; |
| u8 oni = 0; |
| u8 hpdi = 0; |
| u8 cpdi = 0; |
| #endif |
| |
| while (1) { |
| wait_event_interruptible(av8100_event, (av8100_flag != 0)); |
| #ifdef AV8100_PLUGIN_DETECT_VIA_TIMER_INTERRUPTS |
| if ((av8100_flag & AV8100_TIMER_INT_EVENT) && |
| (g_av8100_status.av8100_state >= |
| AV8100_OPMODE_STANDBY)) { |
| hpds_old = &(av8100_globals->hpds_old); |
| cpds_old = &(av8100_globals->cpds_old); |
| cecrx_old = &(av8100_globals->cecrx_old); |
| hdcps_old = &(av8100_globals->hdcps_old); |
| |
| /* STANDBY reg */ |
| if (av8100_reg_stby_r( |
| NULL, |
| NULL, |
| &hpds, |
| &cpds, |
| NULL) != 0) |
| dev_dbg(av8100dev, "av8100_reg_" |
| "stby_r fail\n"); |
| |
| /* TVout plugin change */ |
| if ((cpds == 1) && (cpds != *cpds_old)) { |
| *cpds_old = 1; |
| |
| set_plug_status(AV8100_CVBS_PLUGIN); |
| } else if ((cpds == 0) && (cpds != *cpds_old)) { |
| *cpds_old = 0; |
| |
| clr_plug_status(AV8100_CVBS_PLUGIN); |
| } |
| |
| /* HDMI plugin change */ |
| if ((hpds == 1) && (hpds != *hpds_old)) { |
| *hpds_old = 1; |
| |
| set_plug_status(AV8100_HDMI_PLUGIN); |
| } else if ((hpds == 0) && (hpds != *hpds_old)) { |
| *hpds_old = 0; |
| |
| clr_plug_status(AV8100_HDMI_PLUGIN); |
| } |
| |
| /* GENERAL_STATUS reg */ |
| if (av8100_reg_gen_status_r( |
| &cecrx, |
| NULL, |
| NULL, |
| NULL, |
| &hdcps) != 0) |
| dev_dbg(av8100dev, "av8100_reg_" |
| "gen_status_r fail\n"); |
| else { |
| if ((cecrx == 1) && (cecrx != *cecrx_old)) |
| /* Report CEC event */ |
| cec_rx(); |
| *cecrx_old = cecrx; |
| |
| if (hdcps != *hdcps_old) |
| /* Report HDCP status change event */ |
| hdcp_changed(); |
| *hdcps_old = hdcps; |
| } |
| } |
| #else |
| /* STANDBY_PENDING_INTERRUPT */ |
| ret = av8100_register_standby_pending_interrupt_read( |
| &hpdi, |
| &cpdi, |
| &oni, |
| &sid); |
| |
| if (ret) |
| dev_dbg(av8100dev, "av8100_register_standby_" |
| "pending_interrupt_read failed\n"); |
| |
| if (hpdi | cpdi | oni) { |
| /* STANDBY */ |
| ret = av8100_register_standby_read( |
| &cpd, |
| &stby, |
| &hpds, |
| &cpds, |
| &mclkrng); |
| if (ret) |
| dev_dbg(av8100dev, "av8100_register_standby_" |
| "read fail\n"); |
| } |
| |
| if (cpdi) { |
| /* TVout plugin change */ |
| if (cpds) |
| set_plug_status(AV8100_CVBS_PLUGIN); |
| else |
| clr_plug_status(AV8100_CVBS_PLUGIN); |
| } else if (hpdi) { |
| /* HDMI plugin change */ |
| if (hpds) |
| set_plug_status(AV8100_HDMI_PLUGIN); |
| else |
| clr_plug_status(AV8100_HDMI_PLUGIN); |
| } |
| |
| if (hpdi | cpdi | oni) { |
| /* Clear pending interrupts */ |
| ret = av8100_register_standby_pending_interrupt_write( |
| hpdi, |
| cpdi, |
| oni); |
| if (ret) |
| dev_dbg(av8100dev, "av8100_register_standby_" |
| "read fail\n"); |
| } |
| #endif |
| av8100_flag = 0; |
| } |
| |
| return ret; |
| } |
| |
| static irqreturn_t av8100_intr_handler(int irq, void *p) |
| { |
| av8100_flag |= AV8100_INT_EVENT; |
| wake_up_interruptible(&av8100_event); |
| return IRQ_HANDLED; |
| } |
| |
| static u16 av8100_get_te_line_nb( |
| enum av8100_output_CEA_VESA output_video_format) |
| { |
| u16 retval; |
| |
| switch (output_video_format) { |
| case AV8100_CEA1_640X480P_59_94HZ: |
| case AV8100_CEA2_3_720X480P_59_94HZ: |
| retval = AV8100_TE_LINE_NB_30; |
| break; |
| |
| case AV8100_CEA5_1920X1080I_60HZ: |
| case AV8100_CEA6_7_NTSC_60HZ: |
| case AV8100_CEA20_1920X1080I_50HZ: |
| retval = AV8100_TE_LINE_NB_18; |
| break; |
| |
| case AV8100_CEA4_1280X720P_60HZ: |
| retval = AV8100_TE_LINE_NB_21; |
| break; |
| |
| case AV8100_CEA17_18_720X576P_50HZ: |
| retval = AV8100_TE_LINE_NB_40; |
| break; |
| |
| case AV8100_CEA19_1280X720P_50HZ: |
| retval = AV8100_TE_LINE_NB_22; |
| break; |
| |
| case AV8100_CEA21_22_576I_PAL_50HZ: |
| /* Different values below come from LLD, |
| * TODO: check if this is really needed |
| * if not merge with AV8100_CEA6_7_NTSC_60HZ case |
| */ |
| #ifdef CONFIG_AV8100_SDTV |
| retval = AV8100_TE_LINE_NB_18; |
| #else |
| retval = AV8100_TE_LINE_NB_17; |
| #endif |
| break; |
| |
| case AV8100_CEA32_1920X1080P_24HZ: |
| case AV8100_CEA33_1920X1080P_25HZ: |
| case AV8100_CEA34_1920X1080P_30HZ: |
| retval = AV8100_TE_LINE_NB_38; |
| break; |
| |
| case AV8100_CEA60_1280X720P_24HZ: |
| case AV8100_CEA62_1280X720P_30HZ: |
| retval = AV8100_TE_LINE_NB_21; |
| break; |
| |
| case AV8100_CEA14_15_480p_60HZ: |
| case AV8100_VESA14_848X480P_60HZ: |
| case AV8100_CEA61_1280X720P_25HZ: |
| case AV8100_CEA16_1920X1080P_60HZ: |
| case AV8100_CEA31_1920x1080P_50Hz: |
| case AV8100_CEA29_30_576P_50HZ: |
| case AV8100_VESA9_800X600P_60_32HZ: |
| case AV8100_VESA16_1024X768P_60HZ: |
| case AV8100_VESA22_1280X768P_59_99HZ: |
| case AV8100_VESA23_1280X768P_59_87HZ: |
| case AV8100_VESA27_1280X800P_59_91HZ: |
| case AV8100_VESA28_1280X800P_59_81HZ: |
| case AV8100_VESA39_1360X768P_60_02HZ: |
| case AV8100_VESA81_1366X768P_59_79HZ: |
| default: |
| /* TODO */ |
| retval = AV8100_TE_LINE_NB_14; |
| break; |
| } |
| |
| return retval; |
| } |
| |
| static u16 av8100_get_ui_x4( |
| enum av8100_output_CEA_VESA output_video_format) |
| { |
| return AV8100_UI_X4_DEFAULT; |
| } |
| |
| static int av8100_config_video_output_dep(enum av8100_output_CEA_VESA |
| output_format) |
| { |
| int retval = 0; |
| union av8100_configuration config; |
| |
| /* video input */ |
| config.video_input_format.dsi_input_mode = |
| AV8100_HDMI_DSI_COMMAND_MODE; |
| config.video_input_format.input_pixel_format = AV8100_INPUT_PIX_RGB565; |
| config.video_input_format.total_horizontal_pixel = |
| av8100_all_cea[output_format].htotale; |
| config.video_input_format.total_horizontal_active_pixel = |
| av8100_all_cea[output_format].hactive; |
| config.video_input_format.total_vertical_lines = |
| av8100_all_cea[output_format].vtotale; |
| config.video_input_format.total_vertical_active_lines = |
| av8100_all_cea[output_format].vactive; |
| |
| switch (output_format) { |
| case AV8100_CEA5_1920X1080I_60HZ: |
| case AV8100_CEA20_1920X1080I_50HZ: |
| case AV8100_CEA21_22_576I_PAL_50HZ: |
| case AV8100_CEA6_7_NTSC_60HZ: |
| config.video_input_format.video_mode = |
| AV8100_VIDEO_INTERLACE; |
| break; |
| |
| default: |
| config.video_input_format.video_mode = |
| AV8100_VIDEO_PROGRESSIVE; |
| break; |
| } |
| |
| config.video_input_format.nb_data_lane = |
| AV8100_DATA_LANES_USED_2; |
| config.video_input_format.nb_virtual_ch_command_mode = 0; |
| config.video_input_format.nb_virtual_ch_video_mode = 0; |
| config.video_input_format.ui_x4 = av8100_get_ui_x4(output_format); |
| config.video_input_format.TE_line_nb = av8100_get_te_line_nb( |
| output_format); |
| #ifdef CONFIG_AV8100_HWTRIG_I2SDAT3 |
| config.video_input_format.TE_config = AV8100_TE_GPIO_IT; |
| #else |
| config.video_input_format.TE_config = AV8100_TE_IT_LINE; |
| #endif |
| config.video_input_format.master_clock_freq = 0; |
| |
| retval = av8100_conf_prep( |
| AV8100_COMMAND_VIDEO_INPUT_FORMAT, &config); |
| |
| /* DENC */ |
| switch (output_format) { |
| case AV8100_CEA21_22_576I_PAL_50HZ: |
| config.denc_format.cvbs_video_format = AV8100_CVBS_625; |
| config.denc_format.standard_selection = AV8100_PAL_BDGHI; |
| break; |
| |
| case AV8100_CEA6_7_NTSC_60HZ: |
| config.denc_format.cvbs_video_format = AV8100_CVBS_525; |
| config.denc_format.standard_selection = AV8100_NTSC_M; |
| break; |
| |
| default: |
| /* Not supported */ |
| break; |
| } |
| |
| return retval; |
| } |
| |
| static int av8100_config_init(void) |
| { |
| int retval = 0; |
| union av8100_configuration config; |
| |
| dev_dbg(av8100dev, "%s\n", __func__); |
| |
| av8100_config = kzalloc(sizeof(struct av8100_config_t), GFP_KERNEL); |
| if (!av8100_config) { |
| dev_err(av8100dev, "%s: Failed to allocate config\n", __func__); |
| return AV8100_FAIL; |
| } |
| |
| memset(&config, 0, sizeof(union av8100_configuration)); |
| memset(av8100_config, 0, sizeof(union av8100_configuration)); |
| |
| /* Color conversion */ |
| config.color_space_conversion_format = col_cvt_identity; |
| retval = av8100_conf_prep( |
| AV8100_COMMAND_COLORSPACECONVERSION, &config); |
| if (retval) |
| return AV8100_FAIL; |
| |
| /* DENC */ |
| config.denc_format.cvbs_video_format = AV8100_CVBS_625; |
| config.denc_format.standard_selection = AV8100_PAL_BDGHI; |
| config.denc_format.on_off = 0; |
| config.denc_format.macrovision_on_off = 0; |
| config.denc_format.internal_generator = 0; |
| |
| /* Video output */ |
| config.video_output_format.video_output_cea_vesa = |
| AV8100_CEA4_1280X720P_60HZ; |
| |
| retval = av8100_conf_prep( |
| AV8100_COMMAND_VIDEO_OUTPUT_FORMAT, &config); |
| if (retval) |
| return AV8100_FAIL; |
| |
| /* Video input */ |
| av8100_config_video_output_dep( |
| config.video_output_format.video_output_cea_vesa); |
| |
| /* Pattern generator */ |
| config.pattern_generator_format.pattern_audio_mode = |
| AV8100_PATTERN_AUDIO_OFF; |
| config.pattern_generator_format.pattern_type = |
| AV8100_PATTERN_GENERATOR; |
| config.pattern_generator_format.pattern_video_format = |
| AV8100_PATTERN_720P; |
| retval = av8100_conf_prep(AV8100_COMMAND_PATTERNGENERATOR, |
| &config); |
| if (retval) |
| return AV8100_FAIL; |
| |
| /* Audio input */ |
| config.audio_input_format.audio_input_if_format = |
| AV8100_AUDIO_I2SDELAYED_MODE; |
| config.audio_input_format.i2s_input_nb = 1; |
| config.audio_input_format.sample_audio_freq = AV8100_AUDIO_FREQ_48KHZ; |
| config.audio_input_format.audio_word_lg = AV8100_AUDIO_16BITS; |
| config.audio_input_format.audio_format = AV8100_AUDIO_LPCM_MODE; |
| config.audio_input_format.audio_if_mode = AV8100_AUDIO_MASTER; |
| config.audio_input_format.audio_mute = AV8100_AUDIO_MUTE_DISABLE; |
| retval = av8100_conf_prep( |
| AV8100_COMMAND_AUDIO_INPUT_FORMAT, &config); |
| if (retval) |
| return AV8100_FAIL; |
| |
| /* HDMI mode */ |
| config.hdmi_format.hdmi_mode = AV8100_HDMI_ON; |
| config.hdmi_format.hdmi_format = AV8100_HDMI; |
| config.hdmi_format.dvi_format = AV8100_DVI_CTRL_CTL0; |
| retval = av8100_conf_prep(AV8100_COMMAND_HDMI, &config); |
| if (retval) |
| return AV8100_FAIL; |
| |
| /* EDID section readback */ |
| config.edid_section_readback_format.address = 0xA0; |
| config.edid_section_readback_format.block_number = 0; |
| retval = av8100_conf_prep( |
| AV8100_COMMAND_EDID_SECTION_READBACK, &config); |
| if (retval) |
| return AV8100_FAIL; |
| |
| return retval; |
| } |
| |
| static void av8100_config_exit(void) |
| { |
| dev_dbg(av8100dev, "%s\n", __func__); |
| |
| kfree(av8100_config); |
| av8100_config = NULL; |
| } |
| |
| static int av8100_globals_init(void) |
| { |
| dev_dbg(av8100dev, "%s\n", __func__); |
| |
| av8100_globals = kzalloc(sizeof(struct av8100_globals_t), GFP_KERNEL); |
| if (!av8100_globals) { |
| dev_err(av8100dev, "%s: Alloc failure \n", __func__); |
| return AV8100_FAIL; |
| } |
| |
| av8100_globals->denc_off_time = AV8100_DENC_OFF_TIME; |
| av8100_globals->hdmi_off_time = AV8100_HDMI_OFF_TIME; |
| av8100_globals->on_time = AV8100_ON_TIME; |
| av8100_globals->hpdm = AV8100_STANDBY_INTERRUPT_MASK_HPDM_LOW; |
| av8100_globals->cpdm = AV8100_STANDBY_INTERRUPT_MASK_CPDM_LOW; |
| #ifdef AV8100_PLUGIN_DETECT_VIA_TIMER_INTERRUPTS |
| av8100_globals->hpds_old = 0xf; |
| av8100_globals->cpds_old = 0xf; |
| av8100_globals->cecrx_old = 0xf; |
| av8100_globals->hdcps_old = 0xf; |
| #endif |
| |
| return 0; |
| } |
| |
| static void av8100_globals_exit(void) |
| { |
| dev_dbg(av8100dev, "%s\n", __func__); |
| |
| kfree(av8100_globals); |
| av8100_globals = NULL; |
| } |
| |
| static void clr_plug_status(enum av8100_plugin_status status) |
| { |
| g_av8100_status.av8100_plugin_status &= ~status; |
| |
| switch (status) { |
| case AV8100_HDMI_PLUGIN: |
| if (av8100_globals->hdmi_ev_cb) |
| av8100_globals->hdmi_ev_cb( |
| AV8100_HDMI_EVENT_HDMI_PLUGOUT); |
| break; |
| |
| case AV8100_CVBS_PLUGIN: |
| /* TODO */ |
| break; |
| |
| default: |
| break; |
| } |
| } |
| |
| static void set_plug_status(enum av8100_plugin_status status) |
| { |
| g_av8100_status.av8100_plugin_status |= status; |
| |
| switch (status) { |
| case AV8100_HDMI_PLUGIN: |
| if (av8100_globals->hdmi_ev_cb) |
| av8100_globals->hdmi_ev_cb( |
| AV8100_HDMI_EVENT_HDMI_PLUGIN); |
| break; |
| |
| case AV8100_CVBS_PLUGIN: |
| /* TODO */ |
| break; |
| |
| default: |
| break; |
| } |
| } |
| |
| static void cec_rx(void) |
| { |
| if (av8100_globals->hdmi_ev_cb) |
| av8100_globals->hdmi_ev_cb(AV8100_HDMI_EVENT_CEC); |
| } |
| |
| static void hdcp_changed(void) |
| { |
| if (av8100_globals->hdmi_ev_cb) |
| av8100_globals->hdmi_ev_cb(AV8100_HDMI_EVENT_HDCP); |
| } |
| |
| static void av8100_set_state(enum av8100_operating_mode state) |
| { |
| g_av8100_status.av8100_state = state; |
| if (state <= AV8100_OPMODE_STANDBY) { |
| clr_plug_status(AV8100_HDMI_PLUGIN); |
| clr_plug_status(AV8100_CVBS_PLUGIN); |
| g_av8100_status.hdmi_on = false; |
| } |
| } |
| |
| /** |
| * write_single_byte() - Write a single byte to av8100 |
| * through i2c interface. |
| * @client: i2c client structure |
| * @reg: register offset |
| * @data: data byte to be written |
| * |
| * This funtion uses smbus byte write API to write a single byte to av8100 |
| **/ |
| static int write_single_byte(struct i2c_client *client, u8 reg, |
| u8 data) |
| { |
| int ret; |
| |
| ret = i2c_smbus_write_byte_data(client, reg, data); |
| if (ret < 0) |
| dev_dbg(av8100dev, "i2c smbus write byte failed\n"); |
| |
| return ret; |
| } |
| |
| /** |
| * read_single_byte() - read single byte from av8100 |
| * through i2c interface |
| * @client: i2c client structure |
| * @reg: register offset |
| * @val: register value |
| * |
| * This funtion uses smbus read block API to read single byte from the reg |
| * offset. |
| **/ |
| static int read_single_byte(struct i2c_client *client, u8 reg, u8 *val) |
| { |
| int value; |
| |
| value = i2c_smbus_read_byte_data(client, reg); |
| if (value < 0) { |
| dev_dbg(av8100dev, "i2c smbus read byte failed,read data = %x " |
| "from offset:%x\n" , value, reg); |
| return AV8100_FAIL; |
| } |
| |
| *val = (u8) value; |
| return 0; |
| } |
| |
| /** |
| * write_multi_byte() - Write a multiple bytes to av8100 through |
| * i2c interface. |
| * @client: i2c client structure |
| * @buf: buffer to be written |
| * @nbytes: nunmber of bytes to be written |
| * |
| * This funtion uses smbus block write API's to write n number of bytes to the |
| * av8100 |
| **/ |
| static int write_multi_byte(struct i2c_client *client, u8 reg, |
| u8 *buf, u8 nbytes) |
| { |
| int ret; |
| |
| ret = i2c_smbus_write_i2c_block_data(client, reg, nbytes, buf); |
| if (ret < 0) |
| dev_dbg(av8100dev, "i2c smbus write multi byte error\n"); |
| |
| return ret; |
| } |
| |
| static int configuration_video_input_get(char *buffer, |
| unsigned int *length) |
| { |
| if (!av8100_config) |
| return AV8100_FAIL; |
| |
| buffer[0] = av8100_config->hdmi_video_input_cmd.dsi_input_mode; |
| buffer[1] = av8100_config->hdmi_video_input_cmd.input_pixel_format; |
| buffer[2] = REG_16_8_MSB(av8100_config->hdmi_video_input_cmd. |
| total_horizontal_pixel); |
| buffer[3] = REG_16_8_LSB(av8100_config->hdmi_video_input_cmd. |
| total_horizontal_pixel); |
| buffer[4] = REG_16_8_MSB(av8100_config->hdmi_video_input_cmd. |
| total_horizontal_active_pixel); |
| buffer[5] = REG_16_8_LSB(av8100_config->hdmi_video_input_cmd. |
| total_horizontal_active_pixel); |
| buffer[6] = REG_16_8_MSB(av8100_config->hdmi_video_input_cmd. |
| total_vertical_lines); |
| buffer[7] = REG_16_8_LSB(av8100_config->hdmi_video_input_cmd. |
| total_vertical_lines); |
| buffer[8] = REG_16_8_MSB(av8100_config->hdmi_video_input_cmd. |
| total_vertical_active_lines); |
| buffer[9] = REG_16_8_LSB(av8100_config->hdmi_video_input_cmd. |
| total_vertical_active_lines); |
| buffer[10] = av8100_config->hdmi_video_input_cmd.video_mode; |
| buffer[11] = av8100_config->hdmi_video_input_cmd.nb_data_lane; |
| buffer[12] = av8100_config->hdmi_video_input_cmd. |
| nb_virtual_ch_command_mode; |
| buffer[13] = av8100_config->hdmi_video_input_cmd. |
| nb_virtual_ch_video_mode; |
| buffer[14] = REG_16_8_MSB(av8100_config->hdmi_video_input_cmd. |
| TE_line_nb); |
| buffer[15] = REG_16_8_LSB(av8100_config->hdmi_video_input_cmd. |
| TE_line_nb); |
| buffer[16] = av8100_config->hdmi_video_input_cmd.TE_config; |
| buffer[17] = REG_32_8_MSB(av8100_config->hdmi_video_input_cmd. |
| master_clock_freq); |
| buffer[18] = REG_32_8_MMSB(av8100_config->hdmi_video_input_cmd. |
| master_clock_freq); |
| buffer[19] = REG_32_8_MLSB(av8100_config->hdmi_video_input_cmd. |
| master_clock_freq); |
| buffer[20] = REG_32_8_LSB(av8100_config->hdmi_video_input_cmd. |
| master_clock_freq); |
| buffer[21] = av8100_config->hdmi_video_input_cmd.ui_x4; |
| |
| *length = AV8100_COMMAND_VIDEO_INPUT_FORMAT_SIZE - 1; |
| return 0; |
| |
| } |
| |
| static int configuration_audio_input_get(char *buffer, |
| unsigned int *length) |
| { |
| if (!av8100_config) |
| return AV8100_FAIL; |
| |
| buffer[0] = av8100_config->hdmi_audio_input_cmd. |
| audio_input_if_format; |
| buffer[1] = av8100_config->hdmi_audio_input_cmd.i2s_input_nb; |
| buffer[2] = av8100_config->hdmi_audio_input_cmd.sample_audio_freq; |
| buffer[3] = av8100_config->hdmi_audio_input_cmd.audio_word_lg; |
| buffer[4] = av8100_config->hdmi_audio_input_cmd.audio_format; |
| buffer[5] = av8100_config->hdmi_audio_input_cmd.audio_if_mode; |
| buffer[6] = av8100_config->hdmi_audio_input_cmd.audio_mute; |
| |
| *length = AV8100_COMMAND_AUDIO_INPUT_FORMAT_SIZE - 1; |
| return 0; |
| } |
| |
| static int configuration_video_output_get(char *buffer, |
| unsigned int *length) |
| { |
| if (!av8100_config) |
| return AV8100_FAIL; |
| |
| buffer[0] = av8100_config->hdmi_video_output_cmd. |
| video_output_cea_vesa; |
| |
| if (buffer[0] == AV8100_CUSTOM) { |
| buffer[1] = av8100_config->hdmi_video_output_cmd. |
| vsync_polarity; |
| buffer[2] = av8100_config->hdmi_video_output_cmd. |
| hsync_polarity; |
| buffer[3] = REG_16_8_MSB(av8100_config-> |
| hdmi_video_output_cmd.total_horizontal_pixel); |
| buffer[4] = REG_16_8_LSB(av8100_config-> |
| hdmi_video_output_cmd.total_horizontal_pixel); |
| buffer[5] = REG_16_8_MSB(av8100_config-> |
| hdmi_video_output_cmd.total_horizontal_active_pixel); |
| buffer[6] = REG_16_8_LSB(av8100_config-> |
| hdmi_video_output_cmd.total_horizontal_active_pixel); |
| buffer[7] = REG_16_8_MSB(av8100_config-> |
| hdmi_video_output_cmd.total_vertical_in_half_lines); |
| buffer[8] = REG_16_8_LSB(av8100_config-> |
| hdmi_video_output_cmd.total_vertical_in_half_lines); |
| buffer[9] = REG_16_8_MSB(av8100_config-> |
| hdmi_video_output_cmd. |
| total_vertical_active_in_half_lines); |
| buffer[10] = REG_16_8_LSB(av8100_config-> |
| hdmi_video_output_cmd. |
| total_vertical_active_in_half_lines); |
| buffer[11] = REG_16_8_MSB(av8100_config-> |
| hdmi_video_output_cmd.hsync_start_in_pixel); |
| buffer[12] = REG_16_8_LSB(av8100_config-> |
| hdmi_video_output_cmd.hsync_start_in_pixel); |
| buffer[13] = REG_16_8_MSB(av8100_config-> |
| hdmi_video_output_cmd.hsync_length_in_pixel); |
| buffer[14] = REG_16_8_LSB(av8100_config-> |
| hdmi_video_output_cmd.hsync_length_in_pixel); |
| buffer[15] = REG_16_8_MSB(av8100_config-> |
| hdmi_video_output_cmd.vsync_start_in_half_line); |
| buffer[16] = REG_16_8_LSB(av8100_config-> |
| hdmi_video_output_cmd.vsync_start_in_half_line); |
| buffer[17] = REG_16_8_MSB(av8100_config-> |
| hdmi_video_output_cmd.vsync_length_in_half_line); |
| buffer[18] = REG_16_8_LSB(av8100_config-> |
| hdmi_video_output_cmd.vsync_length_in_half_line); |
| buffer[19] = REG_16_8_MSB(av8100_config-> |
| hdmi_video_output_cmd.hor_video_start_pixel); |
| buffer[20] = REG_16_8_LSB(av8100_config-> |
| hdmi_video_output_cmd.hor_video_start_pixel); |
| buffer[21] = REG_16_8_MSB(av8100_config-> |
| hdmi_video_output_cmd.vert_video_start_pixel); |
| buffer[22] = REG_16_8_LSB(av8100_config-> |
| hdmi_video_output_cmd.vert_video_start_pixel); |
| buffer[23] = av8100_config-> |
| hdmi_video_output_cmd.video_type; |
| buffer[24] = av8100_config-> |
| hdmi_video_output_cmd.pixel_repeat; |
| buffer[25] = REG_32_8_MSB(av8100_config-> |
| hdmi_video_output_cmd.pixel_clock_freq_Hz); |
| buffer[26] = REG_32_8_MMSB(av8100_config-> |
| hdmi_video_output_cmd.pixel_clock_freq_Hz); |
| buffer[27] = REG_32_8_MLSB(av8100_config-> |
| hdmi_video_output_cmd.pixel_clock_freq_Hz); |
| buffer[28] = REG_32_8_LSB(av8100_config-> |
| hdmi_video_output_cmd.pixel_clock_freq_Hz); |
| |
| *length = AV8100_COMMAND_VIDEO_OUTPUT_FORMAT_SIZE - 1; |
| } else { |
| *length = 1; |
| } |
| |
| return 0; |
| } |
| |
| static int configuration_video_scaling_get(char *buffer, |
| unsigned int *length) |
| { |
| if (!av8100_config) |
| return AV8100_FAIL; |
| |
| buffer[0] = REG_16_8_MSB(av8100_config->hdmi_video_scaling_cmd. |
| h_start_in_pixel); |
| buffer[1] = REG_16_8_LSB(av8100_config->hdmi_video_scaling_cmd. |
| h_start_in_pixel); |
| buffer[2] = REG_16_8_MSB(av8100_config->hdmi_video_scaling_cmd. |
| h_stop_in_pixel); |
| buffer[3] = REG_16_8_LSB(av8100_config->hdmi_video_scaling_cmd. |
| h_stop_in_pixel); |
| buffer[4] = REG_16_8_MSB(av8100_config->hdmi_video_scaling_cmd. |
| v_start_in_line); |
| buffer[5] = REG_16_8_LSB(av8100_config->hdmi_video_scaling_cmd. |
| v_start_in_line); |
| buffer[6] = REG_16_8_MSB(av8100_config->hdmi_video_scaling_cmd. |
| v_stop_in_line); |
| buffer[7] = REG_16_8_LSB(av8100_config->hdmi_video_scaling_cmd. |
| v_stop_in_line); |
| buffer[8] = REG_16_8_MSB(av8100_config->hdmi_video_scaling_cmd. |
| h_start_out_pixel); |
| buffer[9] = REG_16_8_LSB(av8100_config->hdmi_video_scaling_cmd |
| .h_start_out_pixel); |
| buffer[10] = REG_16_8_MSB(av8100_config->hdmi_video_scaling_cmd. |
| h_stop_out_pixel); |
| buffer[11] = REG_16_8_LSB(av8100_config->hdmi_video_scaling_cmd. |
| h_stop_out_pixel); |
| buffer[12] = REG_16_8_MSB(av8100_config->hdmi_video_scaling_cmd. |
| v_start_out_line); |
| buffer[13] = REG_16_8_LSB(av8100_config->hdmi_video_scaling_cmd. |
| v_start_out_line); |
| buffer[14] = REG_16_8_MSB(av8100_config->hdmi_video_scaling_cmd. |
| v_stop_out_line); |
| buffer[15] = REG_16_8_LSB(av8100_config->hdmi_video_scaling_cmd. |
| v_stop_out_line); |
| |
| *length = AV8100_COMMAND_VIDEO_SCALING_FORMAT_SIZE - 1; |
| return 0; |
| } |
| |
| static int configuration_colorspace_conversion_get(char *buffer, |
| unsigned int *length) |
| { |
| if (!av8100_config) |
| return AV8100_FAIL; |
| |
| buffer[0] = REG_12_8_MSB(av8100_config-> |
| hdmi_color_space_conversion_cmd.c0); |
| buffer[1] = REG_16_8_LSB(av8100_config-> |
| hdmi_color_space_conversion_cmd.c0); |
| buffer[2] = REG_12_8_MSB(av8100_config-> |
| hdmi_color_space_conversion_cmd.c1); |
| buffer[3] = REG_16_8_LSB(av8100_config-> |
| hdmi_color_space_conversion_cmd.c1); |
| buffer[4] = REG_12_8_MSB(av8100_config-> |
| hdmi_color_space_conversion_cmd.c2); |
| buffer[5] = REG_16_8_LSB(av8100_config-> |
| hdmi_color_space_conversion_cmd.c2); |
| buffer[6] = REG_12_8_MSB(av8100_config-> |
| hdmi_color_space_conversion_cmd.c3); |
| buffer[7] = REG_16_8_LSB(av8100_config-> |
| hdmi_color_space_conversion_cmd.c3); |
| buffer[8] = REG_12_8_MSB(av8100_config-> |
| hdmi_color_space_conversion_cmd.c4); |
| buffer[9] = REG_16_8_LSB(av8100_config-> |
| hdmi_color_space_conversion_cmd.c4); |
| buffer[10] = REG_12_8_MSB(av8100_config-> |
| hdmi_color_space_conversion_cmd.c5); |
| buffer[11] = REG_16_8_LSB(av8100_config-> |
| hdmi_color_space_conversion_cmd.c5); |
| buffer[12] = REG_12_8_MSB(av8100_config-> |
| hdmi_color_space_conversion_cmd.c6); |
| buffer[13] = REG_16_8_LSB(av8100_config-> |
| hdmi_color_space_conversion_cmd.c6); |
| buffer[14] = REG_12_8_MSB(av8100_config-> |
| hdmi_color_space_conversion_cmd.c7); |
| buffer[15] = REG_16_8_LSB(av8100_config-> |
| hdmi_color_space_conversion_cmd.c7); |
| buffer[16] = REG_12_8_MSB(av8100_config-> |
| hdmi_color_space_conversion_cmd.c8); |
| buffer[17] = REG_16_8_LSB(av8100_config-> |
| hdmi_color_space_conversion_cmd.c8); |
| buffer[18] = REG_10_8_MSB(av8100_config-> |
| hdmi_color_space_conversion_cmd.aoffset); |
| buffer[19] = REG_16_8_LSB(av8100_config-> |
| hdmi_color_space_conversion_cmd.aoffset); |
| buffer[20] = REG_10_8_MSB(av8100_config-> |
| hdmi_color_space_conversion_cmd.boffset); |
| buffer[21] = REG_16_8_LSB(av8100_config-> |
| hdmi_color_space_conversion_cmd.boffset); |
| buffer[22] = REG_10_8_MSB(av8100_config-> |
| hdmi_color_space_conversion_cmd.coffset); |
| buffer[23] = REG_16_8_LSB(av8100_config-> |
| hdmi_color_space_conversion_cmd.coffset); |
| buffer[24] = av8100_config->hdmi_color_space_conversion_cmd.lmax; |
| buffer[25] = av8100_config->hdmi_color_space_conversion_cmd.lmin; |
| buffer[26] = av8100_config->hdmi_color_space_conversion_cmd.cmax; |
| buffer[27] = av8100_config->hdmi_color_space_conversion_cmd.cmin; |
| |
| *length = AV8100_COMMAND_COLORSPACECONVERSION_SIZE - 1; |
| return 0; |
| } |
| |
| static int configuration_cec_message_write_get(char *buffer, |
| unsigned int *length) |
| { |
| if (!av8100_config) |
| return AV8100_FAIL; |
| |
| buffer[0] = av8100_config->hdmi_cec_message_write_cmd.buffer_length; |
| memcpy(&buffer[1], av8100_config->hdmi_cec_message_write_cmd.buffer, |
| HDMI_CEC_MESSAGE_WRITE_BUFFER_SIZE); |
| |
| *length = AV8100_COMMAND_CEC_MESSAGE_WRITE_SIZE - 1; |
| return 0; |
| } |
| |
| static int configuration_cec_message_read_get(char *buffer, |
| unsigned int *length) |
| { |
| if (!av8100_config) |
| return AV8100_FAIL; |
| |
| /* No buffer data */ |
| *length = AV8100_COMMAND_CEC_MESSAGE_READ_BACK_SIZE - 1; |
| return 0; |
| } |
| |
| static int configuration_denc_get(char *buffer, |
| unsigned int *length) |
| { |
| if (!av8100_config) |
| return AV8100_FAIL; |
| |
| buffer[0] = av8100_config->hdmi_denc_cmd.cvbs_video_format; |
| buffer[1] = av8100_config->hdmi_denc_cmd.standard_selection; |
| buffer[2] = av8100_config->hdmi_denc_cmd.on_off; |
| buffer[3] = av8100_config->hdmi_denc_cmd.macrovision_on_off; |
| buffer[4] = av8100_config->hdmi_denc_cmd.internal_generator; |
| |
| *length = AV8100_COMMAND_DENC_SIZE - 1; |
| return 0; |
| } |
| |
| static int configuration_hdmi_get(char *buffer, unsigned int *length) |
| { |
| if (!av8100_config) |
| return AV8100_FAIL; |
| |
| buffer[0] = av8100_config->hdmi_cmd.hdmi_mode; |
| buffer[1] = av8100_config->hdmi_cmd.hdmi_format; |
| buffer[2] = av8100_config->hdmi_cmd.dvi_format; |
| |
| *length = AV8100_COMMAND_HDMI_SIZE - 1; |
| return 0; |
| } |
| |
| static int configuration_hdcp_sendkey_get(char *buffer, |
| unsigned int *length) |
| { |
| if (!av8100_config) |
| return AV8100_FAIL; |
| |
| buffer[0] = av8100_config->hdmi_hdcp_send_key_cmd.key_number; |
| memcpy(&buffer[1], av8100_config->hdmi_hdcp_send_key_cmd.data, |
| av8100_config->hdmi_hdcp_send_key_cmd.data_len); |
| |
| *length = av8100_config->hdmi_hdcp_send_key_cmd.data_len + 1; |
| return 0; |
| } |
| |
| static int configuration_hdcp_management_get(char *buffer, |
| unsigned int *length) |
| { |
| if (!av8100_config) |
| return AV8100_FAIL; |
| |
| buffer[0] = av8100_config->hdmi_hdcp_management_format_cmd.req_type; |
| buffer[1] = av8100_config->hdmi_hdcp_management_format_cmd.req_encr; |
| buffer[2] = av8100_config->hdmi_hdcp_management_format_cmd.encr_use; |
| |
| *length = AV8100_COMMAND_HDCP_MANAGEMENT_SIZE - 1; |
| return 0; |
| } |
| |
| static int configuration_infoframe_get(char *buffer, |
| unsigned int *length) |
| { |
| if (!av8100_config) |
| return AV8100_FAIL; |
| |
| buffer[0] = av8100_config->hdmi_infoframes_cmd.type; |
| buffer[1] = av8100_config->hdmi_infoframes_cmd.version; |
| buffer[2] = av8100_config->hdmi_infoframes_cmd.length; |
| buffer[3] = av8100_config->hdmi_infoframes_cmd.crc; |
| memcpy(&buffer[4], av8100_config->hdmi_infoframes_cmd.data, |
| HDMI_INFOFRAME_DATA_SIZE); |
| |
| *length = AV8100_COMMAND_INFOFRAMES_SIZE - 1; |
| return 0; |
| } |
| |
| static int av8100_edid_section_readback_get(char *buffer, unsigned int *length) |
| { |
| buffer[0] = av8100_config->hdmi_edid_section_readback_cmd.address; |
| buffer[1] = av8100_config->hdmi_edid_section_readback_cmd. |
| block_number; |
| |
| *length = AV8100_COMMAND_EDID_SECTION_READBACK_SIZE - 1; |
| return 0; |
| } |
| |
| static int configuration_pattern_generator_get(char *buffer, |
| unsigned int *length) |
| { |
| if (!av8100_config) |
| return AV8100_FAIL; |
| |
| buffer[0] = av8100_config->hdmi_pattern_generator_cmd.pattern_type; |
| buffer[1] = av8100_config->hdmi_pattern_generator_cmd. |
| pattern_video_format; |
| buffer[2] = av8100_config->hdmi_pattern_generator_cmd. |
| pattern_audio_mode; |
| |
| *length = AV8100_COMMAND_PATTERNGENERATOR_SIZE - 1; |
| return 0; |
| } |
| |
| static int configuration_fuse_aes_key_get(char *buffer, |
| unsigned int *length) |
| { |
| if (!av8100_config) |
| return AV8100_FAIL; |
| |
| buffer[0] = av8100_config->hdmi_fuse_aes_key_cmd.fuse_operation; |
| memcpy(&buffer[1], av8100_config->hdmi_fuse_aes_key_cmd.key, |
| HDMI_FUSE_AES_KEY_SIZE); |
| |
| *length = AV8100_COMMAND_FUSE_AES_KEY_SIZE - 1; |
| return 0; |
| } |
| |
| static int get_command_return_data(struct i2c_client *i2c, |
| enum av8100_command_type command_type, |
| u8 *command_buffer, |
| u8 *buffer_length, |
| u8 *buffer) |
| { |
| int retval = 0; |
| char val; |
| int index = 0; |
| |
| /* Get the first return byte */ |
| retval = read_single_byte(i2c, AV8100_COMMAND_OFFSET, &val); |
| if (retval) |
| goto get_command_return_data_fail1r; |
| |
| if (val != (0x80 | command_type)) { |
| retval = AV8100_FAIL; |
| goto get_command_return_data_fail1v; |
| } |
| |
| switch (command_type) { |
| case AV8100_COMMAND_VIDEO_INPUT_FORMAT: |
| case AV8100_COMMAND_AUDIO_INPUT_FORMAT: |
| case AV8100_COMMAND_VIDEO_OUTPUT_FORMAT: |
| case AV8100_COMMAND_VIDEO_SCALING_FORMAT: |
| case AV8100_COMMAND_COLORSPACECONVERSION: |
| case AV8100_COMMAND_CEC_MESSAGE_WRITE: |
| case AV8100_COMMAND_DENC: |
| case AV8100_COMMAND_HDMI: |
| case AV8100_COMMAND_HDCP_SENDKEY: |
| case AV8100_COMMAND_INFOFRAMES: |
| case AV8100_COMMAND_PATTERNGENERATOR: |
| /* Get the second return byte */ |
| retval = read_single_byte(i2c, |
| AV8100_COMMAND_OFFSET + 1, &val); |
| if (retval) |
| goto get_command_return_data_fail2r; |
| |
| if (val) { |
| retval = AV8100_FAIL; |
| goto get_command_return_data_fail2v; |
| } |
| break; |
| |
| case AV8100_COMMAND_CEC_MESSAGE_READ_BACK: |
| if ((buffer == NULL) || (buffer_length == NULL)) { |
| retval = AV8100_FAIL; |
| goto get_command_return_data_fail; |
| } |
| |
| /* Get the return buffer length */ |
| retval = read_single_byte(i2c, |
| AV8100_COMMAND_OFFSET + CEC_ADDR_OFFSET, &val); |
| if (retval) |
| goto get_command_return_data_fail; |
| |
| /* TODO: buffer_length is always zero */ |
| /* *buffer_length = val;*/ |
| dev_dbg(av8100dev, "cec buflen:%d\n", val); |
| *buffer_length = val; |
| |
| if (*buffer_length > |
| HDMI_CEC_READ_MAXSIZE) { |
| dev_dbg(av8100dev, "CEC size too large %d\n", |
| *buffer_length); |
| *buffer_length = HDMI_CEC_READ_MAXSIZE; |
| } |
| |
| #ifdef AV8100_DEBUG_EXTRA |
| dev_dbg(av8100dev, "return data: "); |
| #endif |
| |
| /* Get the return buffer */ |
| for (index = 0; index < *buffer_length; ++index) { |
| retval = read_single_byte(i2c, |
| AV8100_COMMAND_OFFSET + CEC_ADDR_OFFSET + 1 |
| + index, |
| &val); |
| if (retval) { |
| *buffer_length = 0; |
| goto get_command_return_data_fail; |
| } else { |
| *(buffer + index) = val; |
| #ifdef AV8100_DEBUG_EXTRA |
| dev_dbg(av8100dev, "%02x ", *(buffer + index)); |
| #endif |
| } |
| } |
| #ifdef AV8100_DEBUG_EXTRA |
| dev_dbg(av8100dev, "\n"); |
| #endif |
| break; |
| |
| case AV8100_COMMAND_HDCP_MANAGEMENT: |
| /* Get the second return byte */ |
| retval = read_single_byte(i2c, |
| AV8100_COMMAND_OFFSET + 1, &val); |
| if (retval) { |
| goto get_command_return_data_fail2r; |
| } else { |
| /* Check the second return byte */ |
| if (val) |
| goto get_command_return_data_fail2v; |
| } |
| |
| if ((buffer == NULL) || (buffer_length == NULL)) |
| /* Ignore return data */ |
| break; |
| |
| /* Get the return buffer length */ |
| if (command_buffer[0] == |
| HDMI_REQUEST_FOR_REVOCATION_LIST_INPUT) { |
| *buffer_length = 0x1F; |
| } else { |
| *buffer_length = 0x0; |
| } |
| |
| #ifdef AV8100_DEBUG_EXTRA |
| dev_dbg(av8100dev, "return data: "); |
| #endif |
| /* Get the return buffer */ |
| for (index = 0; index < *buffer_length; ++index) { |
| retval = read_single_byte(i2c, |
| AV8100_COMMAND_OFFSET + 2 + index, |
| &val); |
| if (retval) { |
| *buffer_length = 0; |
| goto get_command_return_data_fail; |
| } else { |
| *(buffer + index) = val; |
| #ifdef AV8100_DEBUG_EXTRA |
| dev_dbg(av8100dev, "%02x ", *(buffer + index)); |
| #endif |
| } |
| } |
| #ifdef AV8100_DEBUG_EXTRA |
| dev_dbg(av8100dev, "\n"); |
| #endif |
| break; |
| |
| case AV8100_COMMAND_EDID_SECTION_READBACK: |
| if ((buffer == NULL) || (buffer_length == NULL)) { |
| retval = AV8100_FAIL; |
| goto get_command_return_data_fail; |
| } |
| |
| /* Return buffer length is fixed */ |
| *buffer_length = 0x80; |
| |
| #ifdef AV8100_DEBUG_EXTRA |
| dev_dbg(av8100dev, "return data: "); |
| #endif |
| /* Get the return buffer */ |
| for (index = 0; index < *buffer_length; ++index) { |
| retval = read_single_byte(i2c, |
| AV8100_COMMAND_OFFSET + 1 + index, |
| &val); |
| if (retval) { |
| *buffer_length = 0; |
| goto get_command_return_data_fail; |
| } else { |
| *(buffer + index) = val; |
| #ifdef AV8100_DEBUG_EXTRA |
| dev_dbg(av8100dev, "%02x ", *(buffer + index)); |
| #endif |
| } |
| } |
| #ifdef AV8100_DEBUG_EXTRA |
| dev_dbg(av8100dev, "\n"); |
| #endif |
| break; |
| |
| case AV8100_COMMAND_FUSE_AES_KEY: |
| if ((buffer == NULL) || (buffer_length == NULL)) { |
| retval = AV8100_FAIL; |
| goto get_command_return_data_fail; |
| } |
| |
| /* Get the second return byte */ |
| retval = read_single_byte(i2c, |
| AV8100_COMMAND_OFFSET + 1, &val); |
| if (retval) |
| goto get_command_return_data_fail2r; |
| |
| /* Check the second return byte */ |
| if (val) { |
| retval = AV8100_FAIL; |
| goto get_command_return_data_fail2v; |
| } |
| |
| /* Return buffer length is fixed */ |
| *buffer_length = 0x2; |
| |
| /* Get CRC */ |
| retval = read_single_byte(i2c, |
| AV8100_COMMAND_OFFSET + 1, &val); |
| if (retval) |
| goto get_command_return_data_fail; |
| |
| *(buffer + 0) = val; |
| #ifdef AV8100_DEBUG_EXTRA |
| dev_dbg(av8100dev, "CRC:%02x ", val); |
| #endif |
| |
| /* Get programmed status */ |
| retval = read_single_byte(i2c, |
| AV8100_COMMAND_OFFSET + 1, &val); |
| if (retval) |
| goto get_command_return_data_fail; |
| |
| *(buffer + 1) = val; |
| #ifdef AV8100_DEBUG_EXTRA |
| dev_dbg(av8100dev, "programmed:%02x ", val); |
| #endif |
| break; |
| |
| default: |
| retval = AV8100_INVALID_COMMAND; |
| break; |
| } |
| |
| return retval; |
| get_command_return_data_fail1r: |
| dev_dbg(av8100dev, "%s Reading first return byte failed\n", __func__); |
| return retval; |
| get_command_return_data_fail1v: |
| dev_dbg(av8100dev, "%s First return byte is wrong:%x\n", __func__, val); |
| return retval; |
| get_command_return_data_fail2r: |
| dev_dbg(av8100dev, "%s Reading 2nd return byte failed\n", __func__); |
| return retval; |
| get_command_return_data_fail2v: |
| dev_dbg(av8100dev, "%s 2nd return byte is wrong:%x\n", __func__, val); |
| return retval; |
| get_command_return_data_fail: |
| dev_dbg(av8100dev, "%s FAIL\n", __func__); |
| return retval; |
| } |
| |
| static int av8100_powerup1(void) |
| { |
| int retval = 0; |
| |
| /* Reset av8100 */ |
| gpio_set_value(GPIO_AV8100_RSTN, 1); |
| av8100_set_state(AV8100_OPMODE_STANDBY); |
| |
| /* Get chip version */ |
| retval = av8100_reg_stby_pend_int_r(NULL, NULL, NULL, &chip_version); |
| if (retval) { |
| dev_err(av8100dev, "Failed to read chip version\n"); |
| return -EFAULT; |
| } |
| |
| dev_dbg(av8100dev, "av8100 chip version:%d\n", chip_version); |
| |
| switch (chip_version) { |
| case AV8100_CHIPVER_1: |
| case AV8100_CHIPVER_2: |
| break; |
| |
| default: |
| dev_err(av8100dev, "Unsupported av8100 chip version:%d\n", |
| chip_version); |
| return -EFAULT; |
| break; |
| } |
| |
| return retval; |
| } |
| |
| static int av8100_powerup2(void) |
| { |
| int retval = 0; |
| |
| /* Master clock timing, running, search for plug */ |
| retval = av8100_reg_stby_w(AV8100_STANDBY_CPD_HIGH, |
| AV8100_STANDBY_STBY_HIGH, AV8100_MASTER_CLOCK_TIMING); |
| if (retval) { |
| dev_err(av8100dev, |
| "Failed to write the value to av8100 register\n"); |
| return -EFAULT; |
| } |
| |
| /* ON time & OFF time on 5v HDMI plug detect */ |
| retval = av8100_reg_hdmi_5_volt_time_w( |
| av8100_globals->denc_off_time, |
| av8100_globals->hdmi_off_time, |
| av8100_globals->on_time); |
| if (retval) { |
| dev_err(av8100dev, |
| "Failed to write the value to av8100 register\n"); |
| return -EFAULT; |
| } |
| |
| av8100_set_state(AV8100_OPMODE_SCAN); |
| |
| return retval; |
| } |
| |
| int av8100_powerup(void) |
| { |
| if (av8100_powerup1()) { |
| dev_err(av8100dev, "av8100_powerup1 fail\n"); |
| return -EFAULT; |
| } |
| |
| return av8100_powerup2(); |
| } |
| |
| int av8100_powerdown(void) |
| { |
| gpio_set_value(GPIO_AV8100_RSTN, 0); |
| av8100_set_state(AV8100_OPMODE_SHUTDOWN); |
| |
| return 0; |
| } |
| |
| int av8100_download_firmware(char *fw_buff, int nbytes, |
| enum interface_type if_type) |
| { |
| int retval = 0; |
| int temp = 0x0; |
| int increment = 15; |
| int index = 0; |
| int size = 0x0; |
| int tempnext = 0x0; |
| char val = 0x0; |
| char CheckSum = 0; |
| int cnt = 10; |
| struct i2c_client *i2c; |
| u8 cecrec; |
| u8 cectrx; |
| u8 uc; |
| u8 onuvb; |
| u8 hdcps; |
| u8 fdl; |
| u8 hld; |
| u8 wa; |
| u8 ra; |
| |
| if (!av8100_config) { |
| retval = AV8100_FAIL; |
| goto av8100_download_firmware_out; |
| } |
| |
| if (fw_buff == NULL) { |
| switch (chip_version) { |
| case AV8100_CHIPVER_1: |
| fw_buff = av8100_fw_buff_v1; |
| nbytes = AV8100_FW_SIZE_V1; |
| break; |
| |
| case AV8100_CHIPVER_2: |
| default: |
| fw_buff = av8100_fw_buff_v2; |
| nbytes = AV8100_FW_SIZE_V2; |
| break; |
| } |
| } |
| |
| i2c = av8100_config->client; |
| |
| /* Enable firmware download */ |
| retval = av8100_reg_gen_ctrl_w( |
| AV8100_GENERAL_CONTROL_FDL_HIGH, |
| AV8100_GENERAL_CONTROL_HLD_HIGH, |
| AV8100_GENERAL_CONTROL_WA_LOW, |
| AV8100_GENERAL_CONTROL_RA_LOW); |
| if (retval) { |
| dev_err(av8100dev, |
| "Failed to write the value to av8100 register\n"); |
| return -EFAULT; |
| } |
| |
| retval = av8100_reg_gen_ctrl_r(&fdl, &hld, &wa, &ra); |
| if (retval) { |
| dev_err(av8100dev, |
| "Failed to read the value from av8100 register\n"); |
| return -EFAULT; |
| } else { |
| dev_dbg(av8100dev, "GENERAL_CONTROL_REG register fdl:%d " |
| "hld:%d wa:%d ra:%d\n", fdl, hld, wa, ra); |
| } |
| |
| LOCK_AV8100_HW; |
| |
| temp = nbytes % increment; |
| for (size = 0; size < (nbytes-temp); size = size + increment, |
| index += increment) { |
| if (if_type == I2C_INTERFACE) { |
| retval = write_multi_byte(i2c, |
| AV8100_FIRMWARE_DOWNLOAD_ENTRY, fw_buff + size, |
| increment); |
| if (retval) { |
| dev_dbg(av8100dev, "Failed to download the " |
| "av8100 firmware\n"); |
| retval = -EFAULT; |
| UNLOCK_AV8100_HW; |
| goto av8100_download_firmware_out; |
| } |
| } else if (if_type == DSI_INTERFACE) { |
| dev_dbg(av8100dev, |
| "DSI_INTERFACE is currently not supported\n"); |
| UNLOCK_AV8100_HW; |
| goto av8100_download_firmware_out; |
| } else { |
| retval = AV8100_INVALID_INTERFACE; |
| UNLOCK_AV8100_HW; |
| goto av8100_download_firmware_out; |
| } |
| |
| for (tempnext = size; tempnext < (increment+size); tempnext++) |
| av8100_receivetab[tempnext] = fw_buff[tempnext]; |
| } |
| |
| /* Transfer last firmware bytes */ |
| if (if_type == I2C_INTERFACE) { |
| retval = write_multi_byte(i2c, |
| AV8100_FIRMWARE_DOWNLOAD_ENTRY, fw_buff + size, temp); |
| if (retval) { |
| dev_dbg(av8100dev, |
| "Failed to download the av8100 firmware\n"); |
| retval = -EFAULT; |
| UNLOCK_AV8100_HW; |
| goto av8100_download_firmware_out; |
| } |
| } else if (if_type == DSI_INTERFACE) { |
| /* TODO: Add support for DSI firmware download */ |
| retval = AV8100_INVALID_INTERFACE; |
| UNLOCK_AV8100_HW; |
| goto av8100_download_firmware_out; |
| } else { |
| retval = AV8100_INVALID_INTERFACE; |
| UNLOCK_AV8100_HW; |
| goto av8100_download_firmware_out; |
| } |
| |
| for (tempnext = size; tempnext < (size+temp); tempnext++) |
| av8100_receivetab[tempnext] = fw_buff[tempnext]; |
| |
| /* check transfer*/ |
| for (size = 0; size < nbytes; size++) { |
| CheckSum = CheckSum ^ fw_buff[size]; |
| if (av8100_receivetab[size] != fw_buff[size]) { |
| dev_dbg(av8100dev, ">Fw download fail....i=%d\n", size); |
| dev_dbg(av8100dev, "Transm = %x, Receiv = %x\n", |
| fw_buff[size], av8100_receivetab[size]); |
| } |
| } |
| |
| UNLOCK_AV8100_HW; |
| |
| retval = av8100_reg_fw_dl_entry_r(&val); |
| if (retval) { |
| dev_dbg(av8100dev, |
| "Failed to read the value from the av8100 register\n"); |
| retval = -EFAULT; |
| goto av8100_download_firmware_out; |
| } |
| |
| dev_dbg(av8100dev, "CheckSum:%x,val:%x\n", CheckSum, val); |
| |
| if (CheckSum != val) { |
| dev_dbg(av8100dev, |
| ">Fw downloading.... FAIL CheckSum issue\n"); |
| dev_dbg(av8100dev, "Checksum = %d\n", CheckSum); |
| dev_dbg(av8100dev, "Checksum read: %d\n", val); |
| retval = AV8100_FWDOWNLOAD_FAIL; |
| goto av8100_download_firmware_out; |
| } else { |
| dev_dbg(av8100dev, ">Fw downloading.... success\n"); |
| } |
| |
| /* Set to idle mode */ |
| av8100_reg_gen_ctrl_w(AV8100_GENERAL_CONTROL_FDL_LOW, |
| AV8100_GENERAL_CONTROL_HLD_LOW, AV8100_GENERAL_CONTROL_WA_LOW, |
| AV8100_GENERAL_CONTROL_RA_LOW); |
| if (retval) { |
| dev_dbg(av8100dev, |
| "Failed to write the value to the av8100 register\n"); |
| retval = -EFAULT; |
| goto av8100_download_firmware_out; |
| } |
| |
| /* Wait Internal Micro controler ready */ |
| cnt = 3; |
| retval = av8100_reg_gen_status_r(&cecrec, &cectrx, &uc, |
| &onuvb, &hdcps); |
| while ((retval == 0) && (uc != 0x1) && (cnt-- > 0)) { |
| dev_dbg(av8100dev, "av8100 wait2\n"); |
| /* TODO */ |
| for (temp = 0; temp < 0xFFFFF; temp++) |
| ; |
| |
| retval = av8100_reg_gen_status_r(&cecrec, &cectrx, |
| &uc, &onuvb, &hdcps); |
| } |
| |
| if (retval) { |
| dev_dbg(av8100dev, |
| "Failed to read the value from the av8100 register\n"); |
| retval = -EFAULT; |
| goto av8100_download_firmware_out; |
| } |
| |
| av8100_set_state(AV8100_OPMODE_IDLE); |
| |
| av8100_download_firmware_out: |
| return retval; |
| } |
| |
| int av8100_disable_interrupt(void) |
| { |
| int retval; |
| struct i2c_client *i2c; |
| |
| if (!av8100_config) { |
| retval = AV8100_FAIL; |
| goto av8100_disable_interrupt_out; |
| } |
| |
| i2c = av8100_config->client; |
| |
| retval = av8100_reg_stby_pend_int_w( |
| AV8100_STANDBY_PENDING_INTERRUPT_HPDI_LOW, |
| AV8100_STANDBY_PENDING_INTERRUPT_CPDI_LOW, |
| AV8100_STANDBY_PENDING_INTERRUPT_ONI_LOW); |
| if (retval) { |
| dev_dbg(av8100dev, |
| "Failed to write the value to av8100 register\n"); |
| retval = -EFAULT; |
| goto av8100_disable_interrupt_out; |
| } |
| |
| retval = av8100_reg_gen_int_mask_w( |
| AV8100_GENERAL_INTERRUPT_MASK_EOCM_LOW, |
| AV8100_GENERAL_INTERRUPT_MASK_VSIM_LOW, |
| AV8100_GENERAL_INTERRUPT_MASK_VSOM_LOW, |
| AV8100_GENERAL_INTERRUPT_MASK_CECM_LOW, |
| AV8100_GENERAL_INTERRUPT_MASK_HDCPM_LOW, |
| AV8100_GENERAL_INTERRUPT_MASK_UOVBM_LOW, |
| AV8100_GENERAL_INTERRUPT_MASK_TEM_LOW); |
| if (retval) { |
| dev_dbg(av8100dev, |
| "Failed to write the value to av8100 register\n"); |
| retval = -EFAULT; |
| goto av8100_disable_interrupt_out; |
| } |
| |
| retval = av8100_reg_stby_int_mask_w( |
| AV8100_STANDBY_INTERRUPT_MASK_HPDM_LOW, |
| AV8100_STANDBY_INTERRUPT_MASK_CPDM_LOW, |
| AV8100_STANDBY_INTERRUPT_MASK_STBYGPIOCFG_INPUT, |
| AV8100_STANDBY_INTERRUPT_MASK_IPOL_LOW); |
| if (retval) { |
| dev_dbg(av8100dev, |
| "Failed to write the value to av8100 register\n"); |
| retval = -EFAULT; |
| goto av8100_disable_interrupt_out; |
| } |
| |
| #ifdef AV8100_PLUGIN_DETECT_VIA_TIMER_INTERRUPTS |
| del_timer(&av8100_timer); |
| |
| if (av8100_globals) { |
| /* Reset to be able to detect changes */ |
| av8100_globals->hpds_old = HPDS_INVALID; |
| av8100_globals->cpds_old = CPDS_INVALID; |
| av8100_globals->cecrx_old = CECRX_INVALID; |
| } |
| #endif |
| |
| |
| av8100_disable_interrupt_out: |
| return retval; |
| } |
| |
| int av8100_enable_interrupt(void) |
| { |
| int retval; |
| struct i2c_client *i2c; |
| |
| if (!av8100_config) { |
| retval = AV8100_FAIL; |
| goto av8100_enable_interrupt_out; |
| } |
| |
| i2c = av8100_config->client; |
| |
| retval = av8100_reg_stby_pend_int_w( |
| AV8100_STANDBY_PENDING_INTERRUPT_HPDI_LOW, |
| AV8100_STANDBY_PENDING_INTERRUPT_CPDI_LOW, |
| AV8100_STANDBY_PENDING_INTERRUPT_ONI_LOW); |
| if (retval) { |
| dev_dbg(av8100dev, |
| "Failed to write the value to av8100 register\n"); |
| retval = -EFAULT; |
| goto av8100_enable_interrupt_out; |
| } |
| |
| retval = av8100_reg_gen_int_mask_w( |
| AV8100_GENERAL_INTERRUPT_MASK_EOCM_LOW, |
| AV8100_GENERAL_INTERRUPT_MASK_VSIM_LOW, |
| AV8100_GENERAL_INTERRUPT_MASK_VSOM_LOW, |
| AV8100_GENERAL_INTERRUPT_MASK_CECM_LOW, |
| AV8100_GENERAL_INTERRUPT_MASK_HDCPM_LOW, |
| AV8100_GENERAL_INTERRUPT_MASK_UOVBM_LOW, |
| AV8100_GENERAL_INTERRUPT_MASK_TEM_HIGH); |
| if (retval) { |
| dev_dbg(av8100dev, |
| "Failed to write the value to av8100 register\n"); |
| retval = -EFAULT; |
| goto av8100_enable_interrupt_out; |
| } |
| |
| retval = av8100_reg_stby_int_mask_w( |
| av8100_globals->hpdm, |
| av8100_globals->cpdm, |
| AV8100_STANDBY_INTERRUPT_MASK_STBYGPIOCFG_INPUT, |
| AV8100_STANDBY_INTERRUPT_MASK_IPOL_LOW); |
| if (retval) { |
| dev_dbg(av8100dev, |
| "Failed to write the value to av8100 register\n"); |
| retval = -EFAULT; |
| goto av8100_enable_interrupt_out; |
| } |
| |
| #ifdef AV8100_PLUGIN_DETECT_VIA_TIMER_INTERRUPTS |
| init_timer(&av8100_timer); |
| av8100_timer.expires = jiffies + AV8100_TIMER_INTERRUPT_POLLING_TIME; |
| av8100_timer.function = av8100_timer_int; |
| av8100_timer.data = 0; |
| add_timer(&av8100_timer); |
| #endif |
| |
| av8100_enable_interrupt_out: |
| return retval; |
| } |
| |
| static int register_write_internal(u8 offset, u8 value) |
| { |
| int retval; |
| struct i2c_client *i2c; |
| |
| if (!av8100_config) { |
| retval = AV8100_FAIL; |
| goto av8100_register_write_out; |
| } |
| |
| i2c = av8100_config->client; |
| |
| /* Write to register */ |
| retval = write_single_byte(i2c, offset, value); |
| if (retval) { |
| dev_dbg(av8100dev, |
| "Failed to write the value to av8100 register\n"); |
| retval = -EFAULT; |
| } |
| |
| av8100_register_write_out: |
| return retval; |
| } |
| |
| int av8100_reg_stby_w( |
| u8 cpd, u8 stby, u8 mclkrng) |
| { |
| int retval; |
| u8 val; |
| |
| LOCK_AV8100_HW; |
| |
| /* Set register value */ |
| val = AV8100_STANDBY_CPD(cpd) | AV8100_STANDBY_STBY(stby) | |
| AV8100_STANDBY_MCLKRNG(mclkrng); |
| |
| /* Write to register */ |
| retval = register_write_internal(AV8100_STANDBY, val); |
| UNLOCK_AV8100_HW; |
| return retval; |
| } |
| |
| int av8100_reg_hdmi_5_volt_time_w(u8 denc_off, u8 hdmi_off, u8 on) |
| { |
| int retval; |
| u8 val; |
| |
| LOCK_AV8100_HW; |
| |
| /* Set register value. |
| * chip_version == 1 have one common off time |
| * chip_version > 1 support different off time for hdmi and tvout. */ |
| if (chip_version == 1) |
| val = AV8100_HDMI_5_VOLT_TIME_OFF_TIME(hdmi_off) | |
| AV8100_HDMI_5_VOLT_TIME_ON_TIME(on); |
| else |
| val = AV8100_HDMI_5_VOLT_TIME_DAC_OFF_TIME(denc_off) | |
| AV8100_HDMI_5_VOLT_TIME_SU_OFF_TIME(hdmi_off) | |
| AV8100_HDMI_5_VOLT_TIME_ON_TIME(on); |
| |
| /* Write to register */ |
| retval = register_write_internal(AV8100_HDMI_5_VOLT_TIME, val); |
| |
| /* Set vars */ |
| if (chip_version > 1) |
| av8100_globals->denc_off_time = denc_off; |
| |
| av8100_globals->hdmi_off_time = hdmi_off; |
| av8100_globals->on_time = on; |
| |
| UNLOCK_AV8100_HW; |
| return retval; |
| } |
| |
| int av8100_reg_stby_int_mask_w( |
| u8 hpdm, u8 cpdm, u8 stbygpiocfg, u8 ipol) |
| { |
| int retval; |
| u8 val; |
| |
| LOCK_AV8100_HW; |
| |
| /* Set register value */ |
| val = AV8100_STANDBY_INTERRUPT_MASK_HPDM(hpdm) | |
| AV8100_STANDBY_INTERRUPT_MASK_CPDM(cpdm) | |
| AV8100_STANDBY_INTERRUPT_MASK_STBYGPIOCFG(stbygpiocfg) | |
| AV8100_STANDBY_INTERRUPT_MASK_IPOL(ipol); |
| |
| /* Write to register */ |
| retval = register_write_internal(AV8100_STANDBY_INTERRUPT_MASK, val); |
| |
| av8100_globals->hpdm = hpdm; |
| av8100_globals->cpdm = cpdm; |
| |
| UNLOCK_AV8100_HW; |
| return retval; |
| } |
| |
| int av8100_reg_stby_pend_int_w( |
| u8 hpdi, u8 cpdi, u8 oni) |
| { |
| int retval; |
| u8 val; |
| |
| LOCK_AV8100_HW; |
| |
| /* Set register value */ |
| val = AV8100_STANDBY_PENDING_INTERRUPT_HPDI(hpdi) | |
| AV8100_STANDBY_PENDING_INTERRUPT_CPDI(cpdi) | |
| AV8100_STANDBY_PENDING_INTERRUPT_ONI(oni); |
| |
| /* Write to register */ |
| retval = register_write_internal(AV8100_STANDBY_PENDING_INTERRUPT, val); |
| |
| UNLOCK_AV8100_HW; |
| return retval; |
| } |
| |
| int av8100_reg_gen_int_mask_w( |
| u8 eocm, u8 vsim, u8 vsom, u8 cecm, u8 hdcpm, u8 uovbm, u8 tem) |
| { |
| int retval; |
| u8 val; |
| |
| LOCK_AV8100_HW; |
| |
| /* Set register value */ |
| val = AV8100_GENERAL_INTERRUPT_MASK_EOCM(eocm) | |
| AV8100_GENERAL_INTERRUPT_MASK_VSIM(vsim) | |
| AV8100_GENERAL_INTERRUPT_MASK_VSOM(vsom) | |
| AV8100_GENERAL_INTERRUPT_MASK_CECM(cecm) | |
| AV8100_GENERAL_INTERRUPT_MASK_HDCPM(hdcpm) | |
| AV8100_GENERAL_INTERRUPT_MASK_UOVBM(uovbm) | |
| AV8100_GENERAL_INTERRUPT_MASK_TEM(tem); |
| |
| /* Write to register */ |
| retval = register_write_internal(AV8100_GENERAL_INTERRUPT_MASK, val); |
| |
| UNLOCK_AV8100_HW; |
| return retval; |
| } |
| |
| int av8100_reg_gen_int_w( |
| u8 eoci, u8 vsii, u8 vsoi, u8 ceci, u8 hdcpi, u8 uovbi) |
| { |
| int retval; |
| u8 val; |
| |
| LOCK_AV8100_HW; |
| |
| /* Set register value */ |
| val = AV8100_GENERAL_INTERRUPT_EOCI(eoci) | |
| AV8100_GENERAL_INTERRUPT_VSII(vsii) | |
| AV8100_GENERAL_INTERRUPT_VSOI(vsoi) | |
| AV8100_GENERAL_INTERRUPT_CECI(ceci) | |
| AV8100_GENERAL_INTERRUPT_HDCPI(hdcpi) | |
| AV8100_GENERAL_INTERRUPT_UOVBI(uovbi); |
| |
| /* Write to register */ |
| retval = register_write_internal(AV8100_GENERAL_INTERRUPT, val); |
| UNLOCK_AV8100_HW; |
| return retval; |
| } |
| |
| int av8100_reg_gpio_conf_w( |
| u8 dat3dir, u8 dat3val, u8 dat2dir, u8 dat2val, u8 dat1dir, |
| u8 dat1val, u8 ucdbg) |
| { |
| int retval; |
| u8 val; |
| |
| LOCK_AV8100_HW; |
| |
| /* Set register value */ |
| val = AV8100_GPIO_CONFIGURATION_DAT3DIR(dat3dir) | |
| AV8100_GPIO_CONFIGURATION_DAT3VAL(dat3val) | |
| AV8100_GPIO_CONFIGURATION_DAT2DIR(dat2dir) | |
| AV8100_GPIO_CONFIGURATION_DAT2VAL(dat2val) | |
| AV8100_GPIO_CONFIGURATION_DAT1DIR(dat1dir) | |
| AV8100_GPIO_CONFIGURATION_DAT1VAL(dat1val) | |
| AV8100_GPIO_CONFIGURATION_UCDBG(ucdbg); |
| |
| /* Write to register */ |
| retval = register_write_internal(AV8100_GPIO_CONFIGURATION, val); |
| UNLOCK_AV8100_HW; |
| return retval; |
| } |
| |
| int av8100_reg_gen_ctrl_w( |
| u8 fdl, u8 hld, u8 wa, u8 ra) |
| { |
| int retval; |
| u8 val; |
| |
| LOCK_AV8100_HW; |
| |
| /* Set register value */ |
| val = AV8100_GENERAL_CONTROL_FDL(fdl) | |
| AV8100_GENERAL_CONTROL_HLD(hld) | |
| AV8100_GENERAL_CONTROL_WA(wa) | |
| AV8100_GENERAL_CONTROL_RA(ra); |
| |
| /* Write to register */ |
| retval = register_write_internal(AV8100_GENERAL_CONTROL, val); |
| UNLOCK_AV8100_HW; |
| return retval; |
| } |
| |
| int av8100_reg_fw_dl_entry_w( |
| u8 mbyte_code_entry) |
| { |
| int retval; |
| u8 val; |
| |
| LOCK_AV8100_HW; |
| |
| /* Set register value */ |
| val = AV8100_FIRMWARE_DOWNLOAD_ENTRY_MBYTE_CODE_ENTRY( |
| mbyte_code_entry); |
| |
| /* Write to register */ |
| retval = register_write_internal(AV8100_FIRMWARE_DOWNLOAD_ENTRY, val); |
| UNLOCK_AV8100_HW; |
| return retval; |
| } |
| |
| int av8100_reg_w( |
| u8 offset, u8 value) |
| { |
| int retval = 0; |
| struct i2c_client *i2c; |
| |
| LOCK_AV8100_HW; |
| |
| if (!av8100_config) { |
| retval = AV8100_FAIL; |
| goto av8100_reg_w_out; |
| } |
| |
| i2c = av8100_config->client; |
| |
| /* Write to register */ |
| retval = write_single_byte(i2c, offset, value); |
| if (retval) { |
| dev_dbg(av8100dev, |
| "Failed to write the value to av8100 register\n"); |
| retval = -EFAULT; |
| } |
| |
| av8100_reg_w_out: |
| UNLOCK_AV8100_HW; |
| return retval; |
| } |
| |
| int register_read_internal(u8 offset, u8 *value) |
| { |
| int retval = 0; |
| struct i2c_client *i2c; |
| |
| if (!av8100_config) { |
| retval = AV8100_FAIL; |
| goto av8100_register_read_out; |
| } |
| |
| i2c = av8100_config->client; |
| |
| /* Read from register */ |
| retval = read_single_byte(i2c, offset, value); |
| if (retval) { |
| dev_dbg(av8100dev, |
| "Failed to read the value from av8100 register\n"); |
| retval = -EFAULT; |
| goto av8100_register_read_out; |
| } |
| |
| av8100_register_read_out: |
| return retval; |
| } |
| |
| int av8100_reg_stby_r( |
| u8 *cpd, u8 *stby, u8 *hpds, u8 *cpds, u8 *mclkrng) |
| { |
| int retval; |
| u8 val; |
| |
| LOCK_AV8100_HW; |
| |
| /* Read from register */ |
| retval = register_read_internal(AV8100_STANDBY, &val); |
| |
| /* Set return params */ |
| if (cpd) |
| *cpd = AV8100_STANDBY_CPD_GET(val); |
| if (stby) |
| *stby = AV8100_STANDBY_STBY_GET(val); |
| if (hpds) |
| *hpds = AV8100_STANDBY_HPDS_GET(val); |
| if (cpds) |
| *cpds = AV8100_STANDBY_CPDS_GET(val); |
| if (mclkrng) |
| *mclkrng = AV8100_STANDBY_MCLKRNG_GET(val); |
| |
| UNLOCK_AV8100_HW; |
| return retval; |
| } |
| |
| int av8100_reg_hdmi_5_volt_time_r( |
| u8 *denc_off_time, u8 *hdmi_off_time, u8 *on_time) |
| { |
| int retval; |
| u8 val; |
| |
| LOCK_AV8100_HW; |
| |
| /* Read from register */ |
| retval = register_read_internal(AV8100_HDMI_5_VOLT_TIME, &val); |
| |
| /* Set return params */ |
| if (chip_version == 1) { |
| if (denc_off_time) |
| *denc_off_time = 0; |
| if (hdmi_off_time) |
| *hdmi_off_time = |
| AV8100_HDMI_5_VOLT_TIME_OFF_TIME_GET(val); |
| } else { |
| if (denc_off_time) |
| *denc_off_time = |
| AV8100_HDMI_5_VOLT_TIME_DAC_OFF_TIME_GET(val); |
| if (hdmi_off_time) |
| *hdmi_off_time = |
| AV8100_HDMI_5_VOLT_TIME_SU_OFF_TIME_GET(val); |
| } |
| |
| if (on_time) |
| *on_time = AV8100_HDMI_5_VOLT_TIME_ON_TIME_GET(val); |
| |
| UNLOCK_AV8100_HW; |
| return retval; |
| } |
| |
| int av8100_reg_stby_int_mask_r( |
| u8 *hpdm, u8 *cpdm, u8 *stbygpiocfg, u8 *ipol) |
| { |
| int retval; |
| u8 val; |
| |
| LOCK_AV8100_HW; |
| |
| /* Read from register */ |
| retval = register_read_internal(AV8100_STANDBY_INTERRUPT_MASK, &val); |
| |
| /* Set return params */ |
| if (hpdm) |
| *hpdm = AV8100_STANDBY_INTERRUPT_MASK_HPDM_GET(val); |
| if (cpdm) |
| *cpdm = AV8100_STANDBY_INTERRUPT_MASK_CPDM_GET(val); |
| if (stbygpiocfg) |
| *stbygpiocfg = |
| AV8100_STANDBY_INTERRUPT_MASK_STBYGPIOCFG_GET(val); |
| if (ipol) |
| *ipol = AV8100_STANDBY_INTERRUPT_MASK_IPOL_GET(val); |
| |
| UNLOCK_AV8100_HW; |
| return retval; |
| } |
| |
| int av8100_reg_stby_pend_int_r( |
| u8 *hpdi, u8 *cpdi, u8 *oni, u8 *sid) |
| { |
| int retval; |
| u8 val; |
| |
| LOCK_AV8100_HW; |
| |
| /* Read from register */ |
| retval = register_read_internal(AV8100_STANDBY_PENDING_INTERRUPT, |
| &val); |
| |
| /* Set return params */ |
| if (hpdi) |
| *hpdi = AV8100_STANDBY_PENDING_INTERRUPT_HPDI_GET(val); |
| if (cpdi) |
| *cpdi = AV8100_STANDBY_PENDING_INTERRUPT_CPDI_GET(val); |
| if (oni) |
| *oni = AV8100_STANDBY_PENDING_INTERRUPT_ONI_GET(val); |
| if (sid) |
| *sid = AV8100_STANDBY_PENDING_INTERRUPT_SID_GET(val); |
| |
| UNLOCK_AV8100_HW; |
| return retval; |
| } |
| |
| int av8100_reg_gen_int_mask_r( |
| u8 *eocm, |
| u8 *vsim, |
| u8 *vsom, |
| u8 *cecm, |
| u8 *hdcpm, |
| u8 *uovbm, |
| u8 *tem) |
| { |
| int retval; |
| u8 val; |
| |
| LOCK_AV8100_HW; |
| |
| /* Read from register */ |
| retval = register_read_internal(AV8100_GENERAL_INTERRUPT_MASK, &val); |
| |
| /* Set return params */ |
| if (eocm) |
| *eocm = AV8100_GENERAL_INTERRUPT_MASK_EOCM_GET(val); |
| if (vsim) |
| *vsim = AV8100_GENERAL_INTERRUPT_MASK_VSIM_GET(val); |
| if (vsom) |
| *vsom = AV8100_GENERAL_INTERRUPT_MASK_VSOM_GET(val); |
| if (cecm) |
| *cecm = AV8100_GENERAL_INTERRUPT_MASK_CECM_GET(val); |
| if (hdcpm) |
| *hdcpm = AV8100_GENERAL_INTERRUPT_MASK_HDCPM_GET(val); |
| if (uovbm) |
| *uovbm = AV8100_GENERAL_INTERRUPT_MASK_UOVBM_GET(val); |
| if (tem) |
| *tem = AV8100_GENERAL_INTERRUPT_MASK_TEM_GET(val); |
| |
| UNLOCK_AV8100_HW; |
| return retval; |
| } |
| |
| int av8100_reg_gen_int_r( |
| u8 *eoci, |
| u8 *vsii, |
| u8 *vsoi, |
| u8 *ceci, |
| u8 *hdcpi, |
| u8 *uovbi, |
| u8 *tei) |
| { |
| int retval; |
| u8 val; |
| |
| LOCK_AV8100_HW; |
| |
| /* Read from register */ |
| retval = register_read_internal(AV8100_GENERAL_INTERRUPT, &val); |
| |
| /* Set return params */ |
| if (eoci) |
| *eoci = AV8100_GENERAL_INTERRUPT_EOCI_GET(val); |
| if (vsii) |
| *vsii = AV8100_GENERAL_INTERRUPT_VSII_GET(val); |
| if (vsoi) |
| *vsoi = AV8100_GENERAL_INTERRUPT_VSOI_GET(val); |
| if (ceci) |
| *ceci = AV8100_GENERAL_INTERRUPT_CECI_GET(val); |
| if (hdcpi) |
| *hdcpi = AV8100_GENERAL_INTERRUPT_HDCPI_GET(val); |
| if (uovbi) |
| *uovbi = AV8100_GENERAL_INTERRUPT_UOVBI_GET(val); |
| if (tei) |
| *tei = AV8100_GENERAL_INTERRUPT_TEI_GET(val); |
| |
| UNLOCK_AV8100_HW; |
| return retval; |
| } |
| |
| int av8100_reg_gen_status_r( |
| u8 *cecrec, |
| u8 *cectrx, |
| u8 *uc, |
| u8 *onuvb, |
| u8 *hdcps) |
| { |
| int retval; |
| u8 val; |
| |
| LOCK_AV8100_HW; |
| |
| /* Read from register */ |
| retval = register_read_internal(AV8100_GENERAL_STATUS, &val); |
| |
| /* Set return params */ |
| if (cecrec) |
| *cecrec = AV8100_GENERAL_STATUS_CECREC_GET(val); |
| if (cectrx) |
| *cectrx = AV8100_GENERAL_STATUS_CECTRX_GET(val); |
| if (uc) |
| *uc = AV8100_GENERAL_STATUS_UC_GET(val); |
| if (onuvb) |
| *onuvb = AV8100_GENERAL_STATUS_ONUVB_GET(val); |
| if (hdcps) |
| *hdcps = AV8100_GENERAL_STATUS_HDCPS_GET(val); |
| |
| UNLOCK_AV8100_HW; |
| return retval; |
| } |
| |
| int av8100_reg_gpio_conf_r( |
| u8 *dat3dir, |
| u8 *dat3val, |
| u8 *dat2dir, |
| u8 *dat2val, |
| u8 *dat1dir, |
| u8 *dat1val, |
| u8 *ucdbg) |
| { |
| int retval; |
| u8 val; |
| |
| LOCK_AV8100_HW; |
| |
| /* Read from register */ |
| retval = register_read_internal(AV8100_GPIO_CONFIGURATION, &val); |
| |
| /* Set return params */ |
| if (dat3dir) |
| *dat3dir = AV8100_GPIO_CONFIGURATION_DAT3DIR_GET(val); |
| if (dat3val) |
| *dat3val = AV8100_GPIO_CONFIGURATION_DAT3VAL_GET(val); |
| if (dat2dir) |
| *dat2dir = AV8100_GPIO_CONFIGURATION_DAT2DIR_GET(val); |
| if (dat2val) |
| *dat2val = AV8100_GPIO_CONFIGURATION_DAT2VAL_GET(val); |
| if (dat1dir) |
| *dat1dir = AV8100_GPIO_CONFIGURATION_DAT1DIR_GET(val); |
| if (dat1val) |
| *dat1val = AV8100_GPIO_CONFIGURATION_DAT1VAL_GET(val); |
| if (ucdbg) |
| *ucdbg = AV8100_GPIO_CONFIGURATION_UCDBG_GET(val); |
| |
| UNLOCK_AV8100_HW; |
| return retval; |
| } |
| |
| int av8100_reg_gen_ctrl_r( |
| u8 *fdl, |
| u8 *hld, |
| u8 *wa, |
| u8 *ra) |
| { |
| int retval; |
| u8 val; |
| |
| LOCK_AV8100_HW; |
| |
| /* Read from register */ |
| retval = register_read_internal(AV8100_GENERAL_CONTROL, &val); |
| /* Set return params */ |
| if (fdl) |
| *fdl = AV8100_GENERAL_CONTROL_FDL_GET(val); |
| if (hld) |
| *hld = AV8100_GENERAL_CONTROL_HLD_GET(val); |
| if (wa) |
| *wa = AV8100_GENERAL_CONTROL_WA_GET(val); |
| if (ra) |
| *ra = AV8100_GENERAL_CONTROL_RA_GET(val); |
| |
| UNLOCK_AV8100_HW; |
| return retval; |
| } |
| |
| int av8100_reg_fw_dl_entry_r( |
| u8 *mbyte_code_entry) |
| { |
| int retval; |
| u8 val; |
| |
| LOCK_AV8100_HW; |
| |
| /* Read from register */ |
| retval = register_read_internal(AV8100_FIRMWARE_DOWNLOAD_ENTRY, &val); |
| |
| /* Set return params */ |
| if (mbyte_code_entry) |
| *mbyte_code_entry = |
| AV8100_FIRMWARE_DOWNLOAD_ENTRY_MBYTE_CODE_ENTRY_GET(val); |
| |
| UNLOCK_AV8100_HW; |
| return retval; |
| } |
| |
| int av8100_reg_r( |
| u8 offset, |
| u8 *value) |
| { |
| int retval = 0; |
| struct i2c_client *i2c; |
| |
| LOCK_AV8100_HW; |
| |
| if (!av8100_config) { |
| retval = AV8100_FAIL; |
| goto av8100_register_read_out; |
| } |
| |
| i2c = av8100_config->client; |
| |
| /* Read from register */ |
| retval = read_single_byte(i2c, offset, value); |
| if (retval) { |
| dev_dbg(av8100dev, |
| "Failed to read the value from av8100 register\n"); |
| retval = -EFAULT; |
| goto av8100_register_read_out; |
| } |
| |
| av8100_register_read_out: |
| UNLOCK_AV8100_HW; |
| return retval; |
| } |
| |
| int av8100_conf_get(enum av8100_command_type command_type, |
| union av8100_configuration *config) |
| { |
| if (!av8100_config || !config) |
| return AV8100_FAIL; |
| |
| /* Put configuration data to the corresponding data struct depending |
| * on command type */ |
| switch (command_type) { |
| case AV8100_COMMAND_VIDEO_INPUT_FORMAT: |
| memcpy(&config->video_input_format, |
| &av8100_config->hdmi_video_input_cmd, |
| sizeof(struct av8100_video_input_format_cmd)); |
| break; |
| |
| case AV8100_COMMAND_AUDIO_INPUT_FORMAT: |
| memcpy(&config->audio_input_format, |
| &av8100_config->hdmi_audio_input_cmd, |
| sizeof(struct av8100_audio_input_format_cmd)); |
| break; |
| |
| case AV8100_COMMAND_VIDEO_OUTPUT_FORMAT: |
| memcpy(&config->video_output_format, |
| &av8100_config->hdmi_video_output_cmd, |
| sizeof(struct av8100_video_output_format_cmd)); |
| break; |
| |
| case AV8100_COMMAND_VIDEO_SCALING_FORMAT: |
| memcpy(&config->video_scaling_format, |
| &av8100_config->hdmi_video_scaling_cmd, |
| sizeof(struct av8100_video_scaling_format_cmd)); |
| break; |
| |
| case AV8100_COMMAND_COLORSPACECONVERSION: |
| memcpy(&config->color_space_conversion_format, |
| &av8100_config->hdmi_color_space_conversion_cmd, |
| sizeof(struct |
| av8100_color_space_conversion_format_cmd)); |
| break; |
| |
| case AV8100_COMMAND_CEC_MESSAGE_WRITE: |
| memcpy(&config->cec_message_write_format, |
| &av8100_config->hdmi_cec_message_write_cmd, |
| sizeof(struct av8100_cec_message_write_format_cmd)); |
| break; |
| |
| case AV8100_COMMAND_CEC_MESSAGE_READ_BACK: |
| memcpy(&config->cec_message_read_back_format, |
| &av8100_config->hdmi_cec_message_read_back_cmd, |
| sizeof(struct av8100_cec_message_read_back_format_cmd)); |
| break; |
| |
| case AV8100_COMMAND_DENC: |
| memcpy(&config->denc_format, &av8100_config->hdmi_denc_cmd, |
| sizeof(struct av8100_denc_format_cmd)); |
| break; |
| |
| case AV8100_COMMAND_HDMI: |
| memcpy(&config->hdmi_format, &av8100_config->hdmi_cmd, |
| sizeof(struct av8100_hdmi_cmd)); |
| break; |
| |
| case AV8100_COMMAND_HDCP_SENDKEY: |
| memcpy(&config->hdcp_send_key_format, |
| &av8100_config->hdmi_hdcp_send_key_cmd, |
| sizeof(struct av8100_hdcp_send_key_format_cmd)); |
| break; |
| |
| case AV8100_COMMAND_HDCP_MANAGEMENT: |
| memcpy(&config->hdcp_management_format, |
| &av8100_config->hdmi_hdcp_management_format_cmd, |
| sizeof(struct av8100_hdcp_management_format_cmd)); |
| break; |
| |
| case AV8100_COMMAND_INFOFRAMES: |
| memcpy(&config->infoframes_format, |
| &av8100_config->hdmi_infoframes_cmd, |
| sizeof(struct av8100_infoframes_format_cmd)); |
| break; |
| |
| case AV8100_COMMAND_EDID_SECTION_READBACK: |
| memcpy(&config->edid_section_readback_format, |
| &av8100_config->hdmi_edid_section_readback_cmd, |
| sizeof(struct |
| av8100_edid_section_readback_format_cmd)); |
| break; |
| |
| case AV8100_COMMAND_PATTERNGENERATOR: |
| memcpy(&config->pattern_generator_format, |
| &av8100_config->hdmi_pattern_generator_cmd, |
| sizeof(struct av8100_pattern_generator_format_cmd)); |
| break; |
| |
| case AV8100_COMMAND_FUSE_AES_KEY: |
| memcpy(&config->fuse_aes_key_format, |
| &av8100_config->hdmi_fuse_aes_key_cmd, |
| sizeof(struct av8100_fuse_aes_key_format_cmd)); |
| break; |
| |
| default: |
| return AV8100_FAIL; |
| break; |
| } |
| |
| return 0; |
| } |
| |
| int av8100_conf_prep(enum av8100_command_type command_type, |
| union av8100_configuration *config) |
| { |
| if (!av8100_config || !config) |
| return AV8100_FAIL; |
| |
| /* Put configuration data to the corresponding data struct depending |
| * on command type */ |
| switch (command_type) { |
| case AV8100_COMMAND_VIDEO_INPUT_FORMAT: |
| memcpy(&av8100_config->hdmi_video_input_cmd, |
| &config->video_input_format, |
| sizeof(struct av8100_video_input_format_cmd)); |
| break; |
| |
| case AV8100_COMMAND_AUDIO_INPUT_FORMAT: |
| memcpy(&av8100_config->hdmi_audio_input_cmd, |
| &config->audio_input_format, |
| sizeof(struct av8100_audio_input_format_cmd)); |
| break; |
| |
| case AV8100_COMMAND_VIDEO_OUTPUT_FORMAT: |
| memcpy(&av8100_config->hdmi_video_output_cmd, |
| &config->video_output_format, |
| sizeof(struct av8100_video_output_format_cmd)); |
| |
| /* Set params that depend on video output */ |
| av8100_config_video_output_dep(av8100_config-> |
| hdmi_video_output_cmd.video_output_cea_vesa); |
| break; |
| |
| case AV8100_COMMAND_VIDEO_SCALING_FORMAT: |
| memcpy(&av8100_config->hdmi_video_scaling_cmd, |
| &config->video_scaling_format, |
| sizeof(struct av8100_video_scaling_format_cmd)); |
| break; |
| |
| case AV8100_COMMAND_COLORSPACECONVERSION: |
| memcpy(&av8100_config->hdmi_color_space_conversion_cmd, |
| &config->color_space_conversion_format, |
| sizeof(struct |
| av8100_color_space_conversion_format_cmd)); |
| break; |
| |
| case AV8100_COMMAND_CEC_MESSAGE_WRITE: |
| memcpy(&av8100_config->hdmi_cec_message_write_cmd, |
| &config->cec_message_write_format, |
| sizeof(struct av8100_cec_message_write_format_cmd)); |
| break; |
| |
| case AV8100_COMMAND_CEC_MESSAGE_READ_BACK: |
| memcpy(&av8100_config->hdmi_cec_message_read_back_cmd, |
| &config->cec_message_read_back_format, |
| sizeof(struct av8100_cec_message_read_back_format_cmd)); |
| break; |
| |
| case AV8100_COMMAND_DENC: |
| memcpy(&av8100_config->hdmi_denc_cmd, &config->denc_format, |
| sizeof(struct av8100_denc_format_cmd)); |
| break; |
| |
| case AV8100_COMMAND_HDMI: |
| memcpy(&av8100_config->hdmi_cmd, &config->hdmi_format, |
| sizeof(struct av8100_hdmi_cmd)); |
| break; |
| |
| case AV8100_COMMAND_HDCP_SENDKEY: |
| memcpy(&av8100_config->hdmi_hdcp_send_key_cmd, |
| &config->hdcp_send_key_format, |
| sizeof(struct av8100_hdcp_send_key_format_cmd)); |
| break; |
| |
| case AV8100_COMMAND_HDCP_MANAGEMENT: |
| memcpy(&av8100_config->hdmi_hdcp_management_format_cmd, |
| &config->hdcp_management_format, |
| sizeof(struct av8100_hdcp_management_format_cmd)); |
| break; |
| |
| case AV8100_COMMAND_INFOFRAMES: |
| memcpy(&av8100_config->hdmi_infoframes_cmd, |
| &config->infoframes_format, |
| sizeof(struct av8100_infoframes_format_cmd)); |
| break; |
| |
| case AV8100_COMMAND_EDID_SECTION_READBACK: |
| memcpy(&av8100_config->hdmi_edid_section_readback_cmd, |
| &config->edid_section_readback_format, |
| sizeof(struct |
| av8100_edid_section_readback_format_cmd)); |
| break; |
| |
| case AV8100_COMMAND_PATTERNGENERATOR: |
| memcpy(&av8100_config->hdmi_pattern_generator_cmd, |
| &config->pattern_generator_format, |
| sizeof(struct av8100_pattern_generator_format_cmd)); |
| break; |
| |
| case AV8100_COMMAND_FUSE_AES_KEY: |
| memcpy(&av8100_config->hdmi_fuse_aes_key_cmd, |
| &config->fuse_aes_key_format, |
| sizeof(struct av8100_fuse_aes_key_format_cmd)); |
| break; |
| |
| default: |
| return AV8100_FAIL; |
| break; |
| } |
| |
| return 0; |
| } |
| |
| int av8100_conf_w(enum av8100_command_type command_type, |
| u8 *return_buffer_length, |
| u8 *return_buffer, enum interface_type if_type) |
| { |
| int retval = 0; |
| u8 cmd_buffer[AV8100_COMMAND_MAX_LENGTH]; |
| u32 cmd_length = 0; |
| struct i2c_client *i2c; |
| |
| if (return_buffer_length) |
| *return_buffer_length = 0; |
| |
| if (!av8100_config) |
| return AV8100_FAIL; |
| |
| i2c = av8100_config->client; |
| |
| memset(&cmd_buffer, 0x00, AV8100_COMMAND_MAX_LENGTH); |
| |
| #ifdef AV8100_DEBUG_EXTRA |
| #define PRNK_MODE(_m) dev_dbg(av8100dev, "cmd: " #_m "\n"); |
| #else |
| #define PRNK_MODE(_m) |
| #endif |
| |
| /* Fill the command buffer with configuration data */ |
| switch (command_type) { |
| case AV8100_COMMAND_VIDEO_INPUT_FORMAT: |
| PRNK_MODE(AV8100_COMMAND_VIDEO_INPUT_FORMAT); |
| configuration_video_input_get(cmd_buffer, &cmd_length); |
| break; |
| |
| case AV8100_COMMAND_AUDIO_INPUT_FORMAT: |
| PRNK_MODE(AV8100_COMMAND_AUDIO_INPUT_FORMAT); |
| configuration_audio_input_get(cmd_buffer, &cmd_length); |
| break; |
| |
| case AV8100_COMMAND_VIDEO_OUTPUT_FORMAT: |
| PRNK_MODE(AV8100_COMMAND_VIDEO_OUTPUT_FORMAT); |
| configuration_video_output_get(cmd_buffer, &cmd_length); |
| break; |
| |
| case AV8100_COMMAND_VIDEO_SCALING_FORMAT: |
| PRNK_MODE(AV8100_COMMAND_VIDEO_SCALING_FORMAT); |
| configuration_video_scaling_get(cmd_buffer, |
| &cmd_length); |
| break; |
| |
| case AV8100_COMMAND_COLORSPACECONVERSION: |
| PRNK_MODE(AV8100_COMMAND_COLORSPACECONVERSION); |
| configuration_colorspace_conversion_get(cmd_buffer, |
| &cmd_length); |
| break; |
| |
| case AV8100_COMMAND_CEC_MESSAGE_WRITE: |
| PRNK_MODE(AV8100_COMMAND_CEC_MESSAGE_WRITE); |
| configuration_cec_message_write_get(cmd_buffer, |
| &cmd_length); |
| break; |
| |
| case AV8100_COMMAND_CEC_MESSAGE_READ_BACK: |
| PRNK_MODE(AV8100_COMMAND_CEC_MESSAGE_READ_BACK); |
| configuration_cec_message_read_get(cmd_buffer, |
| &cmd_length); |
| break; |
| |
| case AV8100_COMMAND_DENC: |
| PRNK_MODE(AV8100_COMMAND_DENC); |
| configuration_denc_get(cmd_buffer, &cmd_length); |
| break; |
| |
| case AV8100_COMMAND_HDMI: |
| PRNK_MODE(AV8100_COMMAND_HDMI); |
| configuration_hdmi_get(cmd_buffer, &cmd_length); |
| break; |
| |
| case AV8100_COMMAND_HDCP_SENDKEY: |
| PRNK_MODE(AV8100_COMMAND_HDCP_SENDKEY); |
| configuration_hdcp_sendkey_get(cmd_buffer, &cmd_length); |
| break; |
| |
| case AV8100_COMMAND_HDCP_MANAGEMENT: |
| PRNK_MODE(AV8100_COMMAND_HDCP_MANAGEMENT); |
| configuration_hdcp_management_get(cmd_buffer, |
| &cmd_length); |
| break; |
| |
| case AV8100_COMMAND_INFOFRAMES: |
| PRNK_MODE(AV8100_COMMAND_INFOFRAMES); |
| configuration_infoframe_get(cmd_buffer, &cmd_length); |
| break; |
| |
| case AV8100_COMMAND_EDID_SECTION_READBACK: |
| PRNK_MODE(AV8100_COMMAND_EDID_SECTION_READBACK); |
| av8100_edid_section_readback_get(cmd_buffer, &cmd_length); |
| break; |
| |
| case AV8100_COMMAND_PATTERNGENERATOR: |
| PRNK_MODE(AV8100_COMMAND_PATTERNGENERATOR); |
| configuration_pattern_generator_get(cmd_buffer, |
| &cmd_length); |
| break; |
| |
| case AV8100_COMMAND_FUSE_AES_KEY: |
| PRNK_MODE(AV8100_COMMAND_FUSE_AES_KEY); |
| configuration_fuse_aes_key_get(cmd_buffer, &cmd_length); |
| break; |
| |
| default: |
| dev_dbg(av8100dev, "Invalid command type\n"); |
| retval = AV8100_INVALID_COMMAND; |
| break; |
| } |
| |
| LOCK_AV8100_HW; |
| |
| if (if_type == I2C_INTERFACE) { |
| #ifdef AV8100_DEBUG_EXTRA |
| { |
| int cnt = 0; |
| dev_dbg(av8100dev, "av8100_conf_w cmd_type:%02x length:%02x ", |
| command_type, cmd_length); |
| dev_dbg(av8100dev, "buffer: "); |
| while (cnt < cmd_length) { |
| dev_dbg(av8100dev, "%02x ", cmd_buffer[cnt]); |
| cnt++; |
| } |
| dev_dbg(av8100dev, "\n"); |
| } |
| #endif |
| |
| /* Write the command buffer */ |
| retval = write_multi_byte(i2c, |
| AV8100_COMMAND_OFFSET + 1, cmd_buffer, cmd_length); |
| if (retval) { |
| UNLOCK_AV8100_HW; |
| return retval; |
| } |
| |
| /* Write the command */ |
| retval = write_single_byte(i2c, AV8100_COMMAND_OFFSET, |
| command_type); |
| if (retval) { |
| UNLOCK_AV8100_HW; |
| return retval; |
| } |
| |
| /* TODO */ |
| mdelay(100); |
| |
| retval = get_command_return_data(i2c, command_type, cmd_buffer, |
| return_buffer_length, return_buffer); |
| } else if (if_type == DSI_INTERFACE) { |
| /* TODO */ |
| } else { |
| retval = AV8100_INVALID_INTERFACE; |
| dev_dbg(av8100dev, "Invalid command type\n"); |
| } |
| |
| if (command_type == AV8100_COMMAND_HDMI) { |
| g_av8100_status.hdmi_on = ((av8100_config->hdmi_cmd. |
| hdmi_mode == AV8100_HDMI_ON) && |
| (av8100_config->hdmi_cmd.hdmi_format == AV8100_HDMI)); |
| } |
| |
| UNLOCK_AV8100_HW; |
| return retval; |
| } |
| |
| int av8100_conf_w_raw(enum av8100_command_type command_type, |
| u8 buffer_length, |
| u8 *buffer, |
| u8 *return_buffer_length, |
| u8 *return_buffer) |
| { |
| int retval = 0; |
| struct i2c_client *i2c; |
| |
| LOCK_AV8100_HW; |
| |
| if (return_buffer_length) |
| *return_buffer_length = 0; |
| |
| if (!av8100_config) { |
| retval = AV8100_FAIL; |
| goto av8100_conf_w_raw_out; |
| } |
| |
| i2c = av8100_config->client; |
| |
| /* Write the command buffer */ |
| retval = write_multi_byte(i2c, |
| AV8100_COMMAND_OFFSET + 1, buffer, buffer_length); |
| if (retval) |
| goto av8100_conf_w_raw_out; |
| |
| /* Write the command */ |
| retval = write_single_byte(i2c, AV8100_COMMAND_OFFSET, |
| command_type); |
| if (retval) |
| goto av8100_conf_w_raw_out; |
| |
| /* TODO */ |
| mdelay(100); |
| |
| retval = get_command_return_data(i2c, command_type, buffer, |
| return_buffer_length, return_buffer); |
| |
| av8100_conf_w_raw_out: |
| UNLOCK_AV8100_HW; |
| return retval; |
| } |
| |
| struct av8100_status av8100_status_get(void) |
| { |
| return g_av8100_status; |
| } |
| |
| enum av8100_output_CEA_VESA av8100_video_output_format_get(int xres, |
| int yres, |
| int htot, |
| int vtot, |
| int pixelclk, |
| bool interlaced) |
| { |
| enum av8100_output_CEA_VESA index = 1; |
| int yres_div = !interlaced ? 1 : 2; |
| int hres_div = 1; |
| long freq1; |
| long freq2; |
| |
| /* |
| * 720_576_I need a divider for hact and htot since |
| * these params need to be twice as large as expected in av8100_all_cea, |
| * which is used as input parameter to video input config. |
| */ |
| if ((xres == 720) && (yres == 576) && (interlaced == true)) |
| hres_div = 2; |
| |
| freq1 = 1000000 / htot * 1000000 / vtot / pixelclk + 1; |
| while (index < sizeof(av8100_all_cea)/sizeof(struct av8100_cea)) { |
| freq2 = av8100_all_cea[index].frequence / |
| av8100_all_cea[index].htotale / |
| av8100_all_cea[index].vtotale; |
| |
| dev_dbg(av8100dev, "freq1:%ld freq2:%ld\n", freq1, freq2); |
| if ((xres == av8100_all_cea[index].hactive / hres_div) && |
| (yres == av8100_all_cea[index].vactive * yres_div) && |
| (htot == av8100_all_cea[index].htotale / hres_div) && |
| (vtot == av8100_all_cea[index].vtotale) && |
| (abs(freq1 - freq2) < 2)) { |
| goto av8100_video_output_format_get_out; |
| } |
| index++; |
| } |
| |
| av8100_video_output_format_get_out: |
| dev_dbg(av8100dev, "av8100_video_output_format_get %d %d %d %d %d\n", |
| xres, yres, htot, vtot, index); |
| return index; |
| } |
| |
| void av8100_hdmi_event_cb_set(void (*hdmi_ev_cb)(enum av8100_hdmi_event)) |
| { |
| if (av8100_globals) |
| av8100_globals->hdmi_ev_cb = hdmi_ev_cb; |
| } |
| |
| u8 av8100_ver_get(void) |
| { |
| u8 ret; |
| |
| LOCK_AV8100_HW; |
| ret = chip_version; |
| UNLOCK_AV8100_HW; |
| |
| return ret; |
| } |
| |
| static int av8100_open(struct inode *inode, struct file *filp) |
| { |
| dev_dbg(av8100dev, "av8100_open is called\n"); |
| return 0; |
| } |
| |
| static int av8100_release(struct inode *inode, struct file *filp) |
| { |
| dev_dbg(av8100dev, "av8100_release is called\n"); |
| return 0; |
| } |
| |
| static int av8100_ioctl(struct inode *inode, struct file *file, |
| unsigned int cmd, unsigned long arg) |
| { |
| return 0; |
| } |
| |
| static int __devinit av8100_probe(struct i2c_client *i2cClient, |
| const struct i2c_device_id *id) |
| { |
| int ret = 0; |
| struct av8100_platform_data *pdata = i2cClient->dev.platform_data; |
| |
| av8100dev = &i2cClient->dev; |
| |
| dev_dbg(av8100dev, "%s\n", __func__); |
| |
| g_av8100_status.av8100_state = AV8100_OPMODE_SHUTDOWN; |
| g_av8100_status.av8100_plugin_status = AV8100_PLUGIN_NONE; |
| g_av8100_status.hdmi_on = false; |
| |
| ret = av8100_config_init(); |
| if (ret) { |
| dev_info(av8100dev, "av8100_config_init failed\n"); |
| goto err; |
| } |
| |
| ret = av8100_globals_init(); |
| if (ret) { |
| dev_info(av8100dev, "av8100_globals_init failed\n"); |
| goto err; |
| } |
| |
| if (!i2c_check_functionality(i2cClient->adapter, |
| I2C_FUNC_SMBUS_BYTE_DATA | |
| I2C_FUNC_SMBUS_READ_WORD_DATA)) { |
| ret = -ENODEV; |
| dev_info(av8100dev, "av8100 i2c_check_functionality failed\n"); |
| goto err; |
| } |
| |
| init_waitqueue_head(&av8100_event); |
| |
| av8100_config->client = i2cClient; |
| av8100_config->id = (struct i2c_device_id *) id; |
| i2c_set_clientdata(i2cClient, av8100_config); |
| |
| kthread_run(av8100_thread, NULL, "av8100_thread"); |
| |
| ret = request_irq(pdata->irq, av8100_intr_handler, |
| IRQF_TRIGGER_RISING, "av8100", av8100_config); |
| if (ret) { |
| dev_err(av8100dev, "av8100_hw request_irq %d failed %d\n", |
| pdata->irq, ret); |
| gpio_free(pdata->irq); |
| goto err; |
| } |
| |
| /* Obtain the chip version */ |
| av8100_powerup1(); |
| av8100_powerdown(); |
| |
| return ret; |
| err: |
| return ret; |
| } |
| |
| static int __devexit av8100_remove(struct i2c_client *i2cClient) |
| { |
| dev_dbg(av8100dev, "%s\n", __func__); |
| |
| av8100_config_exit(); |
| av8100_globals_exit(); |
| |
| return 0; |
| } |
| |
| int av8100_init(void) |
| { |
| int ret; |
| |
| pr_debug("%s\n", __func__); |
| |
| ret = i2c_add_driver(&av8100_driver); |
| if (ret) { |
| pr_err("av8100 i2c_add_driver failed\n"); |
| goto av8100_init_err; |
| } |
| |
| ret = misc_register(&av8100_miscdev); |
| if (ret) { |
| pr_err("av8100 misc_register failed\n"); |
| goto av8100_init_err; |
| } |
| |
| hdmi_init(); |
| |
| return ret; |
| |
| av8100_init_err: |
| return ret; |
| } |
| module_init(av8100_init); |
| |
| void av8100_exit(void) |
| { |
| pr_debug("%s\n", __func__); |
| |
| hdmi_exit(); |
| |
| misc_deregister(&av8100_miscdev); |
| i2c_del_driver(&av8100_driver); |
| } |
| module_exit(av8100_exit); |
| |
| MODULE_AUTHOR("Per Persson <per.xb.persson@stericsson.com>"); |
| MODULE_LICENSE("GPL"); |
| MODULE_DESCRIPTION("ST-Ericsson hdmi display driver"); |