diff options
Diffstat (limited to 'drivers/media/i2c/adv7604.c')
| -rw-r--r-- | drivers/media/i2c/adv7604.c | 393 |
1 files changed, 285 insertions, 108 deletions
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 109bc9b12e74..f47555b1000a 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c | |||
| @@ -53,8 +53,7 @@ MODULE_LICENSE("GPL"); | |||
| 53 | /* ADV7604 system clock frequency */ | 53 | /* ADV7604 system clock frequency */ |
| 54 | #define ADV7604_fsc (28636360) | 54 | #define ADV7604_fsc (28636360) |
| 55 | 55 | ||
| 56 | #define DIGITAL_INPUT ((state->prim_mode == ADV7604_PRIM_MODE_HDMI_COMP) || \ | 56 | #define DIGITAL_INPUT (state->mode == ADV7604_MODE_HDMI) |
| 57 | (state->prim_mode == ADV7604_PRIM_MODE_HDMI_GR)) | ||
| 58 | 57 | ||
| 59 | /* | 58 | /* |
| 60 | ********************************************************************** | 59 | ********************************************************************** |
| @@ -68,7 +67,7 @@ struct adv7604_state { | |||
| 68 | struct v4l2_subdev sd; | 67 | struct v4l2_subdev sd; |
| 69 | struct media_pad pad; | 68 | struct media_pad pad; |
| 70 | struct v4l2_ctrl_handler hdl; | 69 | struct v4l2_ctrl_handler hdl; |
| 71 | enum adv7604_prim_mode prim_mode; | 70 | enum adv7604_mode mode; |
| 72 | struct v4l2_dv_timings timings; | 71 | struct v4l2_dv_timings timings; |
| 73 | u8 edid[256]; | 72 | u8 edid[256]; |
| 74 | unsigned edid_blocks; | 73 | unsigned edid_blocks; |
| @@ -77,6 +76,7 @@ struct adv7604_state { | |||
| 77 | struct workqueue_struct *work_queues; | 76 | struct workqueue_struct *work_queues; |
| 78 | struct delayed_work delayed_work_enable_hotplug; | 77 | struct delayed_work delayed_work_enable_hotplug; |
| 79 | bool connector_hdmi; | 78 | bool connector_hdmi; |
| 79 | bool restart_stdi_once; | ||
| 80 | 80 | ||
| 81 | /* i2c clients */ | 81 | /* i2c clients */ |
| 82 | struct i2c_client *i2c_avlink; | 82 | struct i2c_client *i2c_avlink; |
| @@ -106,7 +106,6 @@ static const struct v4l2_dv_timings adv7604_timings[] = { | |||
| 106 | V4L2_DV_BT_CEA_720X576P50, | 106 | V4L2_DV_BT_CEA_720X576P50, |
| 107 | V4L2_DV_BT_CEA_1280X720P24, | 107 | V4L2_DV_BT_CEA_1280X720P24, |
| 108 | V4L2_DV_BT_CEA_1280X720P25, | 108 | V4L2_DV_BT_CEA_1280X720P25, |
| 109 | V4L2_DV_BT_CEA_1280X720P30, | ||
| 110 | V4L2_DV_BT_CEA_1280X720P50, | 109 | V4L2_DV_BT_CEA_1280X720P50, |
| 111 | V4L2_DV_BT_CEA_1280X720P60, | 110 | V4L2_DV_BT_CEA_1280X720P60, |
| 112 | V4L2_DV_BT_CEA_1920X1080P24, | 111 | V4L2_DV_BT_CEA_1920X1080P24, |
| @@ -115,6 +114,7 @@ static const struct v4l2_dv_timings adv7604_timings[] = { | |||
| 115 | V4L2_DV_BT_CEA_1920X1080P50, | 114 | V4L2_DV_BT_CEA_1920X1080P50, |
| 116 | V4L2_DV_BT_CEA_1920X1080P60, | 115 | V4L2_DV_BT_CEA_1920X1080P60, |
| 117 | 116 | ||
| 117 | /* sorted by DMT ID */ | ||
| 118 | V4L2_DV_BT_DMT_640X350P85, | 118 | V4L2_DV_BT_DMT_640X350P85, |
| 119 | V4L2_DV_BT_DMT_640X400P85, | 119 | V4L2_DV_BT_DMT_640X400P85, |
| 120 | V4L2_DV_BT_DMT_720X400P85, | 120 | V4L2_DV_BT_DMT_720X400P85, |
| @@ -164,6 +164,89 @@ static const struct v4l2_dv_timings adv7604_timings[] = { | |||
| 164 | { }, | 164 | { }, |
| 165 | }; | 165 | }; |
| 166 | 166 | ||
| 167 | struct adv7604_video_standards { | ||
| 168 | struct v4l2_dv_timings timings; | ||
| 169 | u8 vid_std; | ||
| 170 | u8 v_freq; | ||
| 171 | }; | ||
| 172 | |||
| 173 | /* sorted by number of lines */ | ||
| 174 | static const struct adv7604_video_standards adv7604_prim_mode_comp[] = { | ||
| 175 | /* { V4L2_DV_BT_CEA_720X480P59_94, 0x0a, 0x00 }, TODO flickering */ | ||
| 176 | { V4L2_DV_BT_CEA_720X576P50, 0x0b, 0x00 }, | ||
| 177 | { V4L2_DV_BT_CEA_1280X720P50, 0x19, 0x01 }, | ||
| 178 | { V4L2_DV_BT_CEA_1280X720P60, 0x19, 0x00 }, | ||
| 179 | { V4L2_DV_BT_CEA_1920X1080P24, 0x1e, 0x04 }, | ||
| 180 | { V4L2_DV_BT_CEA_1920X1080P25, 0x1e, 0x03 }, | ||
| 181 | { V4L2_DV_BT_CEA_1920X1080P30, 0x1e, 0x02 }, | ||
| 182 | { V4L2_DV_BT_CEA_1920X1080P50, 0x1e, 0x01 }, | ||
| 183 | { V4L2_DV_BT_CEA_1920X1080P60, 0x1e, 0x00 }, | ||
| 184 | /* TODO add 1920x1080P60_RB (CVT timing) */ | ||
| 185 | { }, | ||
| 186 | }; | ||
| 187 | |||
| 188 | /* sorted by number of lines */ | ||
| 189 | static const struct adv7604_video_standards adv7604_prim_mode_gr[] = { | ||
| 190 | { V4L2_DV_BT_DMT_640X480P60, 0x08, 0x00 }, | ||
| 191 | { V4L2_DV_BT_DMT_640X480P72, 0x09, 0x00 }, | ||
| 192 | { V4L2_DV_BT_DMT_640X480P75, 0x0a, 0x00 }, | ||
| 193 | { V4L2_DV_BT_DMT_640X480P85, 0x0b, 0x00 }, | ||
| 194 | { V4L2_DV_BT_DMT_800X600P56, 0x00, 0x00 }, | ||
| 195 | { V4L2_DV_BT_DMT_800X600P60, 0x01, 0x00 }, | ||
| 196 | { V4L2_DV_BT_DMT_800X600P72, 0x02, 0x00 }, | ||
| 197 | { V4L2_DV_BT_DMT_800X600P75, 0x03, 0x00 }, | ||
| 198 | { V4L2_DV_BT_DMT_800X600P85, 0x04, 0x00 }, | ||
| 199 | { V4L2_DV_BT_DMT_1024X768P60, 0x0c, 0x00 }, | ||
| 200 | { V4L2_DV_BT_DMT_1024X768P70, 0x0d, 0x00 }, | ||
| 201 | { V4L2_DV_BT_DMT_1024X768P75, 0x0e, 0x00 }, | ||
| 202 | { V4L2_DV_BT_DMT_1024X768P85, 0x0f, 0x00 }, | ||
| 203 | { V4L2_DV_BT_DMT_1280X1024P60, 0x05, 0x00 }, | ||
| 204 | { V4L2_DV_BT_DMT_1280X1024P75, 0x06, 0x00 }, | ||
| 205 | { V4L2_DV_BT_DMT_1360X768P60, 0x12, 0x00 }, | ||
| 206 | { V4L2_DV_BT_DMT_1366X768P60, 0x13, 0x00 }, | ||
| 207 | { V4L2_DV_BT_DMT_1400X1050P60, 0x14, 0x00 }, | ||
| 208 | { V4L2_DV_BT_DMT_1400X1050P75, 0x15, 0x00 }, | ||
| 209 | { V4L2_DV_BT_DMT_1600X1200P60, 0x16, 0x00 }, /* TODO not tested */ | ||
| 210 | /* TODO add 1600X1200P60_RB (not a DMT timing) */ | ||
| 211 | { V4L2_DV_BT_DMT_1680X1050P60, 0x18, 0x00 }, | ||
| 212 | { V4L2_DV_BT_DMT_1920X1200P60_RB, 0x19, 0x00 }, /* TODO not tested */ | ||
| 213 | { }, | ||
| 214 | }; | ||
| 215 | |||
| 216 | /* sorted by number of lines */ | ||
| 217 | static const struct adv7604_video_standards adv7604_prim_mode_hdmi_comp[] = { | ||
| 218 | { V4L2_DV_BT_CEA_720X480P59_94, 0x0a, 0x00 }, | ||
| 219 | { V4L2_DV_BT_CEA_720X576P50, 0x0b, 0x00 }, | ||
| 220 | { V4L2_DV_BT_CEA_1280X720P50, 0x13, 0x01 }, | ||
| 221 | { V4L2_DV_BT_CEA_1280X720P60, 0x13, 0x00 }, | ||
| 222 | { V4L2_DV_BT_CEA_1920X1080P24, 0x1e, 0x04 }, | ||
| 223 | { V4L2_DV_BT_CEA_1920X1080P25, 0x1e, 0x03 }, | ||
| 224 | { V4L2_DV_BT_CEA_1920X1080P30, 0x1e, 0x02 }, | ||
| 225 | { V4L2_DV_BT_CEA_1920X1080P50, 0x1e, 0x01 }, | ||
| 226 | { V4L2_DV_BT_CEA_1920X1080P60, 0x1e, 0x00 }, | ||
| 227 | { }, | ||
| 228 | }; | ||
| 229 | |||
| 230 | /* sorted by number of lines */ | ||
| 231 | static const struct adv7604_video_standards adv7604_prim_mode_hdmi_gr[] = { | ||
| 232 | { V4L2_DV_BT_DMT_640X480P60, 0x08, 0x00 }, | ||
| 233 | { V4L2_DV_BT_DMT_640X480P72, 0x09, 0x00 }, | ||
| 234 | { V4L2_DV_BT_DMT_640X480P75, 0x0a, 0x00 }, | ||
| 235 | { V4L2_DV_BT_DMT_640X480P85, 0x0b, 0x00 }, | ||
| 236 | { V4L2_DV_BT_DMT_800X600P56, 0x00, 0x00 }, | ||
| 237 | { V4L2_DV_BT_DMT_800X600P60, 0x01, 0x00 }, | ||
| 238 | { V4L2_DV_BT_DMT_800X600P72, 0x02, 0x00 }, | ||
| 239 | { V4L2_DV_BT_DMT_800X600P75, 0x03, 0x00 }, | ||
| 240 | { V4L2_DV_BT_DMT_800X600P85, 0x04, 0x00 }, | ||
| 241 | { V4L2_DV_BT_DMT_1024X768P60, 0x0c, 0x00 }, | ||
| 242 | { V4L2_DV_BT_DMT_1024X768P70, 0x0d, 0x00 }, | ||
| 243 | { V4L2_DV_BT_DMT_1024X768P75, 0x0e, 0x00 }, | ||
| 244 | { V4L2_DV_BT_DMT_1024X768P85, 0x0f, 0x00 }, | ||
| 245 | { V4L2_DV_BT_DMT_1280X1024P60, 0x05, 0x00 }, | ||
| 246 | { V4L2_DV_BT_DMT_1280X1024P75, 0x06, 0x00 }, | ||
| 247 | { }, | ||
| 248 | }; | ||
| 249 | |||
| 167 | /* ----------------------------------------------------------------------- */ | 250 | /* ----------------------------------------------------------------------- */ |
| 168 | 251 | ||
| 169 | static inline struct adv7604_state *to_state(struct v4l2_subdev *sd) | 252 | static inline struct adv7604_state *to_state(struct v4l2_subdev *sd) |
| @@ -403,9 +486,19 @@ static inline int edid_read_block(struct v4l2_subdev *sd, unsigned len, u8 *val) | |||
| 403 | struct i2c_client *client = state->i2c_edid; | 486 | struct i2c_client *client = state->i2c_edid; |
| 404 | u8 msgbuf0[1] = { 0 }; | 487 | u8 msgbuf0[1] = { 0 }; |
| 405 | u8 msgbuf1[256]; | 488 | u8 msgbuf1[256]; |
| 406 | struct i2c_msg msg[2] = { { client->addr, 0, 1, msgbuf0 }, | 489 | struct i2c_msg msg[2] = { |
| 407 | { client->addr, 0 | I2C_M_RD, len, msgbuf1 } | 490 | { |
| 408 | }; | 491 | .addr = client->addr, |
| 492 | .len = 1, | ||
| 493 | .buf = msgbuf0 | ||
| 494 | }, | ||
| 495 | { | ||
| 496 | .addr = client->addr, | ||
| 497 | .flags = I2C_M_RD, | ||
| 498 | .len = len, | ||
| 499 | .buf = msgbuf1 | ||
| 500 | }, | ||
| 501 | }; | ||
| 409 | 502 | ||
| 410 | if (i2c_transfer(client->adapter, msg, 2) < 0) | 503 | if (i2c_transfer(client->adapter, msg, 2) < 0) |
| 411 | return -EIO; | 504 | return -EIO; |
| @@ -672,64 +765,144 @@ static int adv7604_s_detect_tx_5v_ctrl(struct v4l2_subdev *sd) | |||
| 672 | ((io_read(sd, 0x6f) & 0x10) >> 4)); | 765 | ((io_read(sd, 0x6f) & 0x10) >> 4)); |
| 673 | } | 766 | } |
| 674 | 767 | ||
| 675 | static void configure_free_run(struct v4l2_subdev *sd, const struct v4l2_bt_timings *timings) | 768 | static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd, |
| 769 | u8 prim_mode, | ||
| 770 | const struct adv7604_video_standards *predef_vid_timings, | ||
| 771 | const struct v4l2_dv_timings *timings) | ||
| 676 | { | 772 | { |
| 773 | struct adv7604_state *state = to_state(sd); | ||
| 774 | int i; | ||
| 775 | |||
| 776 | for (i = 0; predef_vid_timings[i].timings.bt.width; i++) { | ||
| 777 | if (!v4l_match_dv_timings(timings, &predef_vid_timings[i].timings, | ||
| 778 | DIGITAL_INPUT ? 250000 : 1000000)) | ||
| 779 | continue; | ||
| 780 | io_write(sd, 0x00, predef_vid_timings[i].vid_std); /* video std */ | ||
| 781 | io_write(sd, 0x01, (predef_vid_timings[i].v_freq << 4) + | ||
| 782 | prim_mode); /* v_freq and prim mode */ | ||
| 783 | return 0; | ||
| 784 | } | ||
| 785 | |||
| 786 | return -1; | ||
| 787 | } | ||
| 788 | |||
| 789 | static int configure_predefined_video_timings(struct v4l2_subdev *sd, | ||
| 790 | struct v4l2_dv_timings *timings) | ||
| 791 | { | ||
| 792 | struct adv7604_state *state = to_state(sd); | ||
| 793 | int err; | ||
| 794 | |||
| 795 | v4l2_dbg(1, debug, sd, "%s", __func__); | ||
| 796 | |||
| 797 | /* reset to default values */ | ||
| 798 | io_write(sd, 0x16, 0x43); | ||
| 799 | io_write(sd, 0x17, 0x5a); | ||
| 800 | /* disable embedded syncs for auto graphics mode */ | ||
| 801 | cp_write_and_or(sd, 0x81, 0xef, 0x00); | ||
| 802 | cp_write(sd, 0x8f, 0x00); | ||
| 803 | cp_write(sd, 0x90, 0x00); | ||
| 804 | cp_write(sd, 0xa2, 0x00); | ||
| 805 | cp_write(sd, 0xa3, 0x00); | ||
| 806 | cp_write(sd, 0xa4, 0x00); | ||
| 807 | cp_write(sd, 0xa5, 0x00); | ||
| 808 | cp_write(sd, 0xa6, 0x00); | ||
| 809 | cp_write(sd, 0xa7, 0x00); | ||
| 810 | cp_write(sd, 0xab, 0x00); | ||
| 811 | cp_write(sd, 0xac, 0x00); | ||
| 812 | |||
| 813 | switch (state->mode) { | ||
| 814 | case ADV7604_MODE_COMP: | ||
| 815 | case ADV7604_MODE_GR: | ||
| 816 | err = find_and_set_predefined_video_timings(sd, | ||
| 817 | 0x01, adv7604_prim_mode_comp, timings); | ||
| 818 | if (err) | ||
| 819 | err = find_and_set_predefined_video_timings(sd, | ||
| 820 | 0x02, adv7604_prim_mode_gr, timings); | ||
| 821 | break; | ||
| 822 | case ADV7604_MODE_HDMI: | ||
| 823 | err = find_and_set_predefined_video_timings(sd, | ||
| 824 | 0x05, adv7604_prim_mode_hdmi_comp, timings); | ||
| 825 | if (err) | ||
| 826 | err = find_and_set_predefined_video_timings(sd, | ||
| 827 | 0x06, adv7604_prim_mode_hdmi_gr, timings); | ||
| 828 | break; | ||
| 829 | default: | ||
| 830 | v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n", | ||
| 831 | __func__, state->mode); | ||
| 832 | err = -1; | ||
| 833 | break; | ||
| 834 | } | ||
| 835 | |||
| 836 | |||
| 837 | return err; | ||
| 838 | } | ||
| 839 | |||
| 840 | static void configure_custom_video_timings(struct v4l2_subdev *sd, | ||
| 841 | const struct v4l2_bt_timings *bt) | ||
| 842 | { | ||
| 843 | struct adv7604_state *state = to_state(sd); | ||
| 677 | struct i2c_client *client = v4l2_get_subdevdata(sd); | 844 | struct i2c_client *client = v4l2_get_subdevdata(sd); |
| 678 | u32 width = htotal(timings); | 845 | u32 width = htotal(bt); |
| 679 | u32 height = vtotal(timings); | 846 | u32 height = vtotal(bt); |
| 680 | u16 ch1_fr_ll = (((u32)timings->pixelclock / 100) > 0) ? | 847 | u16 cp_start_sav = bt->hsync + bt->hbackporch - 4; |
| 681 | ((width * (ADV7604_fsc / 100)) / ((u32)timings->pixelclock / 100)) : 0; | 848 | u16 cp_start_eav = width - bt->hfrontporch; |
| 849 | u16 cp_start_vbi = height - bt->vfrontporch; | ||
| 850 | u16 cp_end_vbi = bt->vsync + bt->vbackporch; | ||
| 851 | u16 ch1_fr_ll = (((u32)bt->pixelclock / 100) > 0) ? | ||
| 852 | ((width * (ADV7604_fsc / 100)) / ((u32)bt->pixelclock / 100)) : 0; | ||
| 853 | const u8 pll[2] = { | ||
| 854 | 0xc0 | ((width >> 8) & 0x1f), | ||
| 855 | width & 0xff | ||
| 856 | }; | ||
| 682 | 857 | ||
| 683 | v4l2_dbg(2, debug, sd, "%s\n", __func__); | 858 | v4l2_dbg(2, debug, sd, "%s\n", __func__); |
| 684 | 859 | ||
| 685 | cp_write(sd, 0x8f, (ch1_fr_ll >> 8) & 0x7); /* CH1_FR_LL */ | 860 | switch (state->mode) { |
| 686 | cp_write(sd, 0x90, ch1_fr_ll & 0xff); /* CH1_FR_LL */ | 861 | case ADV7604_MODE_COMP: |
| 687 | cp_write(sd, 0xab, (height >> 4) & 0xff); /* CP_LCOUNT_MAX */ | 862 | case ADV7604_MODE_GR: |
| 688 | cp_write(sd, 0xac, (height & 0x0f) << 4); /* CP_LCOUNT_MAX */ | 863 | /* auto graphics */ |
| 689 | /* TODO support interlaced */ | 864 | io_write(sd, 0x00, 0x07); /* video std */ |
| 690 | cp_write(sd, 0x91, 0x10); /* INTERLACED */ | 865 | io_write(sd, 0x01, 0x02); /* prim mode */ |
| 691 | 866 | /* enable embedded syncs for auto graphics mode */ | |
| 692 | /* Should only be set in auto-graphics mode [REF_02 p. 91-92] */ | 867 | cp_write_and_or(sd, 0x81, 0xef, 0x10); |
| 693 | if ((io_read(sd, 0x00) == 0x07) && (io_read(sd, 0x01) == 0x02)) { | ||
| 694 | u16 cp_start_sav, cp_start_eav, cp_start_vbi, cp_end_vbi; | ||
| 695 | const u8 pll[2] = { | ||
| 696 | (0xc0 | ((width >> 8) & 0x1f)), | ||
| 697 | (width & 0xff) | ||
| 698 | }; | ||
| 699 | 868 | ||
| 869 | /* Should only be set in auto-graphics mode [REF_02, p. 91-92] */ | ||
| 700 | /* setup PLL_DIV_MAN_EN and PLL_DIV_RATIO */ | 870 | /* setup PLL_DIV_MAN_EN and PLL_DIV_RATIO */ |
| 701 | /* IO-map reg. 0x16 and 0x17 should be written in sequence */ | 871 | /* IO-map reg. 0x16 and 0x17 should be written in sequence */ |
| 702 | if (adv_smbus_write_i2c_block_data(client, 0x16, 2, pll)) { | 872 | if (adv_smbus_write_i2c_block_data(client, 0x16, 2, pll)) { |
| 703 | v4l2_err(sd, "writing to reg 0x16 and 0x17 failed\n"); | 873 | v4l2_err(sd, "writing to reg 0x16 and 0x17 failed\n"); |
| 704 | return; | 874 | break; |
| 705 | } | 875 | } |
| 706 | 876 | ||
| 707 | /* active video - horizontal timing */ | 877 | /* active video - horizontal timing */ |
| 708 | cp_start_sav = timings->hsync + timings->hbackporch - 4; | ||
| 709 | cp_start_eav = width - timings->hfrontporch; | ||
| 710 | cp_write(sd, 0xa2, (cp_start_sav >> 4) & 0xff); | 878 | cp_write(sd, 0xa2, (cp_start_sav >> 4) & 0xff); |
| 711 | cp_write(sd, 0xa3, ((cp_start_sav & 0x0f) << 4) | ((cp_start_eav >> 8) & 0x0f)); | 879 | cp_write(sd, 0xa3, ((cp_start_sav & 0x0f) << 4) | |
| 880 | ((cp_start_eav >> 8) & 0x0f)); | ||
| 712 | cp_write(sd, 0xa4, cp_start_eav & 0xff); | 881 | cp_write(sd, 0xa4, cp_start_eav & 0xff); |
| 713 | 882 | ||
| 714 | /* active video - vertical timing */ | 883 | /* active video - vertical timing */ |
| 715 | cp_start_vbi = height - timings->vfrontporch; | ||
| 716 | cp_end_vbi = timings->vsync + timings->vbackporch; | ||
| 717 | cp_write(sd, 0xa5, (cp_start_vbi >> 4) & 0xff); | 884 | cp_write(sd, 0xa5, (cp_start_vbi >> 4) & 0xff); |
| 718 | cp_write(sd, 0xa6, ((cp_start_vbi & 0xf) << 4) | ((cp_end_vbi >> 8) & 0xf)); | 885 | cp_write(sd, 0xa6, ((cp_start_vbi & 0xf) << 4) | |
| 886 | ((cp_end_vbi >> 8) & 0xf)); | ||
| 719 | cp_write(sd, 0xa7, cp_end_vbi & 0xff); | 887 | cp_write(sd, 0xa7, cp_end_vbi & 0xff); |
| 720 | } else { | 888 | break; |
| 721 | /* reset to default values */ | 889 | case ADV7604_MODE_HDMI: |
| 722 | io_write(sd, 0x16, 0x43); | 890 | /* set default prim_mode/vid_std for HDMI |
| 723 | io_write(sd, 0x17, 0x5a); | 891 | accoring to [REF_03, c. 4.2] */ |
| 724 | cp_write(sd, 0xa2, 0x00); | 892 | io_write(sd, 0x00, 0x02); /* video std */ |
| 725 | cp_write(sd, 0xa3, 0x00); | 893 | io_write(sd, 0x01, 0x06); /* prim mode */ |
| 726 | cp_write(sd, 0xa4, 0x00); | 894 | break; |
| 727 | cp_write(sd, 0xa5, 0x00); | 895 | default: |
| 728 | cp_write(sd, 0xa6, 0x00); | 896 | v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n", |
| 729 | cp_write(sd, 0xa7, 0x00); | 897 | __func__, state->mode); |
| 898 | break; | ||
| 730 | } | 899 | } |
| 731 | } | ||
| 732 | 900 | ||
| 901 | cp_write(sd, 0x8f, (ch1_fr_ll >> 8) & 0x7); | ||
| 902 | cp_write(sd, 0x90, ch1_fr_ll & 0xff); | ||
| 903 | cp_write(sd, 0xab, (height >> 4) & 0xff); | ||
| 904 | cp_write(sd, 0xac, (height & 0x0f) << 4); | ||
| 905 | } | ||
| 733 | 906 | ||
| 734 | static void set_rgb_quantization_range(struct v4l2_subdev *sd) | 907 | static void set_rgb_quantization_range(struct v4l2_subdev *sd) |
| 735 | { | 908 | { |
| @@ -738,12 +911,7 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) | |||
| 738 | switch (state->rgb_quantization_range) { | 911 | switch (state->rgb_quantization_range) { |
| 739 | case V4L2_DV_RGB_RANGE_AUTO: | 912 | case V4L2_DV_RGB_RANGE_AUTO: |
| 740 | /* automatic */ | 913 | /* automatic */ |
| 741 | if ((hdmi_read(sd, 0x05) & 0x80) || | 914 | if (DIGITAL_INPUT && !(hdmi_read(sd, 0x05) & 0x80)) { |
| 742 | (state->prim_mode == ADV7604_PRIM_MODE_COMP) || | ||
| 743 | (state->prim_mode == ADV7604_PRIM_MODE_RGB)) { | ||
| 744 | /* receiving HDMI or analog signal */ | ||
| 745 | io_write_and_or(sd, 0x02, 0x0f, 0xf0); | ||
| 746 | } else { | ||
| 747 | /* receiving DVI-D signal */ | 915 | /* receiving DVI-D signal */ |
| 748 | 916 | ||
| 749 | /* ADV7604 selects RGB limited range regardless of | 917 | /* ADV7604 selects RGB limited range regardless of |
| @@ -756,6 +924,9 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd) | |||
| 756 | /* RGB full range (0-255) */ | 924 | /* RGB full range (0-255) */ |
| 757 | io_write_and_or(sd, 0x02, 0x0f, 0x10); | 925 | io_write_and_or(sd, 0x02, 0x0f, 0x10); |
| 758 | } | 926 | } |
| 927 | } else { | ||
| 928 | /* receiving HDMI or analog signal, set automode */ | ||
| 929 | io_write_and_or(sd, 0x02, 0x0f, 0xf0); | ||
| 759 | } | 930 | } |
| 760 | break; | 931 | break; |
| 761 | case V4L2_DV_RGB_RANGE_LIMITED: | 932 | case V4L2_DV_RGB_RANGE_LIMITED: |
| @@ -967,8 +1138,10 @@ static int stdi2dv_timings(struct v4l2_subdev *sd, | |||
| 967 | state->aspect_ratio, timings)) | 1138 | state->aspect_ratio, timings)) |
| 968 | return 0; | 1139 | return 0; |
| 969 | 1140 | ||
| 970 | v4l2_dbg(2, debug, sd, "%s: No format candidate found for lcf=%d, bl = %d\n", | 1141 | v4l2_dbg(2, debug, sd, |
| 971 | __func__, stdi->lcf, stdi->bl); | 1142 | "%s: No format candidate found for lcvs = %d, lcf=%d, bl = %d, %chsync, %cvsync\n", |
| 1143 | __func__, stdi->lcvs, stdi->lcf, stdi->bl, | ||
| 1144 | stdi->hs_pol, stdi->vs_pol); | ||
| 972 | return -1; | 1145 | return -1; |
| 973 | } | 1146 | } |
| 974 | 1147 | ||
| @@ -1123,7 +1296,7 @@ static int adv7604_query_dv_timings(struct v4l2_subdev *sd, | |||
| 1123 | adv7604_fill_optional_dv_timings_fields(sd, timings); | 1296 | adv7604_fill_optional_dv_timings_fields(sd, timings); |
| 1124 | } else { | 1297 | } else { |
| 1125 | /* find format | 1298 | /* find format |
| 1126 | * Since LCVS values are inaccurate (REF_03, page 275-276), | 1299 | * Since LCVS values are inaccurate [REF_03, p. 275-276], |
| 1127 | * stdi2dv_timings() is called with lcvs +-1 if the first attempt fails. | 1300 | * stdi2dv_timings() is called with lcvs +-1 if the first attempt fails. |
| 1128 | */ | 1301 | */ |
| 1129 | if (!stdi2dv_timings(sd, &stdi, timings)) | 1302 | if (!stdi2dv_timings(sd, &stdi, timings)) |
| @@ -1135,9 +1308,31 @@ static int adv7604_query_dv_timings(struct v4l2_subdev *sd, | |||
| 1135 | stdi.lcvs -= 2; | 1308 | stdi.lcvs -= 2; |
| 1136 | v4l2_dbg(1, debug, sd, "%s: lcvs - 1 = %d\n", __func__, stdi.lcvs); | 1309 | v4l2_dbg(1, debug, sd, "%s: lcvs - 1 = %d\n", __func__, stdi.lcvs); |
| 1137 | if (stdi2dv_timings(sd, &stdi, timings)) { | 1310 | if (stdi2dv_timings(sd, &stdi, timings)) { |
| 1311 | /* | ||
| 1312 | * The STDI block may measure wrong values, especially | ||
| 1313 | * for lcvs and lcf. If the driver can not find any | ||
| 1314 | * valid timing, the STDI block is restarted to measure | ||
| 1315 | * the video timings again. The function will return an | ||
| 1316 | * error, but the restart of STDI will generate a new | ||
| 1317 | * STDI interrupt and the format detection process will | ||
| 1318 | * restart. | ||
| 1319 | */ | ||
| 1320 | if (state->restart_stdi_once) { | ||
| 1321 | v4l2_dbg(1, debug, sd, "%s: restart STDI\n", __func__); | ||
| 1322 | /* TODO restart STDI for Sync Channel 2 */ | ||
| 1323 | /* enter one-shot mode */ | ||
| 1324 | cp_write_and_or(sd, 0x86, 0xf9, 0x00); | ||
| 1325 | /* trigger STDI restart */ | ||
| 1326 | cp_write_and_or(sd, 0x86, 0xf9, 0x04); | ||
| 1327 | /* reset to continuous mode */ | ||
| 1328 | cp_write_and_or(sd, 0x86, 0xf9, 0x02); | ||
| 1329 | state->restart_stdi_once = false; | ||
| 1330 | return -ENOLINK; | ||
| 1331 | } | ||
| 1138 | v4l2_dbg(1, debug, sd, "%s: format not supported\n", __func__); | 1332 | v4l2_dbg(1, debug, sd, "%s: format not supported\n", __func__); |
| 1139 | return -ERANGE; | 1333 | return -ERANGE; |
| 1140 | } | 1334 | } |
| 1335 | state->restart_stdi_once = true; | ||
| 1141 | } | 1336 | } |
| 1142 | found: | 1337 | found: |
| 1143 | 1338 | ||
| @@ -1166,6 +1361,7 @@ static int adv7604_s_dv_timings(struct v4l2_subdev *sd, | |||
| 1166 | { | 1361 | { |
| 1167 | struct adv7604_state *state = to_state(sd); | 1362 | struct adv7604_state *state = to_state(sd); |
| 1168 | struct v4l2_bt_timings *bt; | 1363 | struct v4l2_bt_timings *bt; |
| 1364 | int err; | ||
| 1169 | 1365 | ||
| 1170 | if (!timings) | 1366 | if (!timings) |
| 1171 | return -EINVAL; | 1367 | return -EINVAL; |
| @@ -1178,12 +1374,20 @@ static int adv7604_s_dv_timings(struct v4l2_subdev *sd, | |||
| 1178 | __func__, (u32)bt->pixelclock); | 1374 | __func__, (u32)bt->pixelclock); |
| 1179 | return -ERANGE; | 1375 | return -ERANGE; |
| 1180 | } | 1376 | } |
| 1377 | |||
| 1181 | adv7604_fill_optional_dv_timings_fields(sd, timings); | 1378 | adv7604_fill_optional_dv_timings_fields(sd, timings); |
| 1182 | 1379 | ||
| 1183 | state->timings = *timings; | 1380 | state->timings = *timings; |
| 1184 | 1381 | ||
| 1185 | /* freerun */ | 1382 | cp_write(sd, 0x91, bt->interlaced ? 0x50 : 0x10); |
| 1186 | configure_free_run(sd, bt); | 1383 | |
| 1384 | /* Use prim_mode and vid_std when available */ | ||
| 1385 | err = configure_predefined_video_timings(sd, timings); | ||
| 1386 | if (err) { | ||
| 1387 | /* custom settings when the video format | ||
| 1388 | does not have prim_mode/vid_std */ | ||
| 1389 | configure_custom_video_timings(sd, bt); | ||
| 1390 | } | ||
| 1187 | 1391 | ||
| 1188 | set_rgb_quantization_range(sd); | 1392 | set_rgb_quantization_range(sd); |
| 1189 | 1393 | ||
| @@ -1203,24 +1407,25 @@ static int adv7604_g_dv_timings(struct v4l2_subdev *sd, | |||
| 1203 | return 0; | 1407 | return 0; |
| 1204 | } | 1408 | } |
| 1205 | 1409 | ||
| 1206 | static void enable_input(struct v4l2_subdev *sd, enum adv7604_prim_mode prim_mode) | 1410 | static void enable_input(struct v4l2_subdev *sd) |
| 1207 | { | 1411 | { |
| 1208 | switch (prim_mode) { | 1412 | struct adv7604_state *state = to_state(sd); |
| 1209 | case ADV7604_PRIM_MODE_COMP: | 1413 | |
| 1210 | case ADV7604_PRIM_MODE_RGB: | 1414 | switch (state->mode) { |
| 1415 | case ADV7604_MODE_COMP: | ||
| 1416 | case ADV7604_MODE_GR: | ||
| 1211 | /* enable */ | 1417 | /* enable */ |
| 1212 | io_write(sd, 0x15, 0xb0); /* Disable Tristate of Pins (no audio) */ | 1418 | io_write(sd, 0x15, 0xb0); /* Disable Tristate of Pins (no audio) */ |
| 1213 | break; | 1419 | break; |
| 1214 | case ADV7604_PRIM_MODE_HDMI_COMP: | 1420 | case ADV7604_MODE_HDMI: |
| 1215 | case ADV7604_PRIM_MODE_HDMI_GR: | ||
| 1216 | /* enable */ | 1421 | /* enable */ |
| 1217 | hdmi_write(sd, 0x1a, 0x0a); /* Unmute audio */ | 1422 | hdmi_write(sd, 0x1a, 0x0a); /* Unmute audio */ |
| 1218 | hdmi_write(sd, 0x01, 0x00); /* Enable HDMI clock terminators */ | 1423 | hdmi_write(sd, 0x01, 0x00); /* Enable HDMI clock terminators */ |
| 1219 | io_write(sd, 0x15, 0xa0); /* Disable Tristate of Pins */ | 1424 | io_write(sd, 0x15, 0xa0); /* Disable Tristate of Pins */ |
| 1220 | break; | 1425 | break; |
| 1221 | default: | 1426 | default: |
| 1222 | v4l2_err(sd, "%s: reserved primary mode 0x%0x\n", | 1427 | v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n", |
| 1223 | __func__, prim_mode); | 1428 | __func__, state->mode); |
| 1224 | break; | 1429 | break; |
| 1225 | } | 1430 | } |
| 1226 | } | 1431 | } |
| @@ -1233,17 +1438,13 @@ static void disable_input(struct v4l2_subdev *sd) | |||
| 1233 | hdmi_write(sd, 0x01, 0x78); /* Disable HDMI clock terminators */ | 1438 | hdmi_write(sd, 0x01, 0x78); /* Disable HDMI clock terminators */ |
| 1234 | } | 1439 | } |
| 1235 | 1440 | ||
| 1236 | static void select_input(struct v4l2_subdev *sd, enum adv7604_prim_mode prim_mode) | 1441 | static void select_input(struct v4l2_subdev *sd) |
| 1237 | { | 1442 | { |
| 1238 | switch (prim_mode) { | 1443 | struct adv7604_state *state = to_state(sd); |
| 1239 | case ADV7604_PRIM_MODE_COMP: | ||
| 1240 | case ADV7604_PRIM_MODE_RGB: | ||
| 1241 | /* set mode and select free run resolution */ | ||
| 1242 | io_write(sd, 0x00, 0x07); /* video std */ | ||
| 1243 | io_write(sd, 0x01, 0x02); /* prim mode */ | ||
| 1244 | /* enable embedded syncs for auto graphics mode */ | ||
| 1245 | cp_write_and_or(sd, 0x81, 0xef, 0x10); | ||
| 1246 | 1444 | ||
| 1445 | switch (state->mode) { | ||
| 1446 | case ADV7604_MODE_COMP: | ||
| 1447 | case ADV7604_MODE_GR: | ||
| 1247 | /* reset ADI recommended settings for HDMI: */ | 1448 | /* reset ADI recommended settings for HDMI: */ |
| 1248 | /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */ | 1449 | /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */ |
| 1249 | hdmi_write(sd, 0x0d, 0x04); /* HDMI filter optimization */ | 1450 | hdmi_write(sd, 0x0d, 0x04); /* HDMI filter optimization */ |
| @@ -1271,16 +1472,7 @@ static void select_input(struct v4l2_subdev *sd, enum adv7604_prim_mode prim_mod | |||
| 1271 | cp_write(sd, 0x40, 0x5c); /* CP core pre-gain control. Graphics mode */ | 1472 | cp_write(sd, 0x40, 0x5c); /* CP core pre-gain control. Graphics mode */ |
| 1272 | break; | 1473 | break; |
| 1273 | 1474 | ||
| 1274 | case ADV7604_PRIM_MODE_HDMI_COMP: | 1475 | case ADV7604_MODE_HDMI: |
| 1275 | case ADV7604_PRIM_MODE_HDMI_GR: | ||
| 1276 | /* set mode and select free run resolution */ | ||
| 1277 | /* video std */ | ||
| 1278 | io_write(sd, 0x00, | ||
| 1279 | (prim_mode == ADV7604_PRIM_MODE_HDMI_GR) ? 0x02 : 0x1e); | ||
| 1280 | io_write(sd, 0x01, prim_mode); /* prim mode */ | ||
| 1281 | /* disable embedded syncs for auto graphics mode */ | ||
| 1282 | cp_write_and_or(sd, 0x81, 0xef, 0x00); | ||
| 1283 | |||
| 1284 | /* set ADI recommended settings for HDMI: */ | 1476 | /* set ADI recommended settings for HDMI: */ |
| 1285 | /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */ | 1477 | /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */ |
| 1286 | hdmi_write(sd, 0x0d, 0x84); /* HDMI filter optimization */ | 1478 | hdmi_write(sd, 0x0d, 0x84); /* HDMI filter optimization */ |
| @@ -1309,7 +1501,8 @@ static void select_input(struct v4l2_subdev *sd, enum adv7604_prim_mode prim_mod | |||
| 1309 | 1501 | ||
| 1310 | break; | 1502 | break; |
| 1311 | default: | 1503 | default: |
| 1312 | v4l2_err(sd, "%s: reserved primary mode 0x%0x\n", __func__, prim_mode); | 1504 | v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n", |
| 1505 | __func__, state->mode); | ||
| 1313 | break; | 1506 | break; |
| 1314 | } | 1507 | } |
| 1315 | } | 1508 | } |
| @@ -1321,26 +1514,13 @@ static int adv7604_s_routing(struct v4l2_subdev *sd, | |||
| 1321 | 1514 | ||
| 1322 | v4l2_dbg(2, debug, sd, "%s: input %d", __func__, input); | 1515 | v4l2_dbg(2, debug, sd, "%s: input %d", __func__, input); |
| 1323 | 1516 | ||
| 1324 | switch (input) { | 1517 | state->mode = input; |
| 1325 | case 0: | ||
| 1326 | /* TODO select HDMI_COMP or HDMI_GR */ | ||
| 1327 | state->prim_mode = ADV7604_PRIM_MODE_HDMI_COMP; | ||
| 1328 | break; | ||
| 1329 | case 1: | ||
| 1330 | state->prim_mode = ADV7604_PRIM_MODE_RGB; | ||
| 1331 | break; | ||
| 1332 | case 2: | ||
| 1333 | state->prim_mode = ADV7604_PRIM_MODE_COMP; | ||
| 1334 | break; | ||
| 1335 | default: | ||
| 1336 | return -EINVAL; | ||
| 1337 | } | ||
| 1338 | 1518 | ||
| 1339 | disable_input(sd); | 1519 | disable_input(sd); |
| 1340 | 1520 | ||
| 1341 | select_input(sd, state->prim_mode); | 1521 | select_input(sd); |
| 1342 | 1522 | ||
| 1343 | enable_input(sd, state->prim_mode); | 1523 | enable_input(sd); |
| 1344 | 1524 | ||
| 1345 | return 0; | 1525 | return 0; |
| 1346 | } | 1526 | } |
| @@ -1549,8 +1729,9 @@ static int adv7604_log_status(struct v4l2_subdev *sd) | |||
| 1549 | v4l2_info(sd, "CP locked: %s\n", no_lock_cp(sd) ? "false" : "true"); | 1729 | v4l2_info(sd, "CP locked: %s\n", no_lock_cp(sd) ? "false" : "true"); |
| 1550 | v4l2_info(sd, "CP free run: %s\n", | 1730 | v4l2_info(sd, "CP free run: %s\n", |
| 1551 | (!!(cp_read(sd, 0xff) & 0x10) ? "on" : "off")); | 1731 | (!!(cp_read(sd, 0xff) & 0x10) ? "on" : "off")); |
| 1552 | v4l2_info(sd, "Prim-mode = 0x%x, video std = 0x%x\n", | 1732 | v4l2_info(sd, "Prim-mode = 0x%x, video std = 0x%x, v_freq = 0x%x\n", |
| 1553 | io_read(sd, 0x01) & 0x0f, io_read(sd, 0x00) & 0x3f); | 1733 | io_read(sd, 0x01) & 0x0f, io_read(sd, 0x00) & 0x3f, |
| 1734 | (io_read(sd, 0x01) & 0x70) >> 4); | ||
| 1554 | 1735 | ||
| 1555 | v4l2_info(sd, "-----Video Timings-----\n"); | 1736 | v4l2_info(sd, "-----Video Timings-----\n"); |
| 1556 | if (read_stdi(sd, &stdi)) | 1737 | if (read_stdi(sd, &stdi)) |
| @@ -1712,9 +1893,9 @@ static int adv7604_core_init(struct v4l2_subdev *sd) | |||
| 1712 | cp_write(sd, 0xba, (pdata->hdmi_free_run_mode << 1) | 0x01); /* HDMI free run */ | 1893 | cp_write(sd, 0xba, (pdata->hdmi_free_run_mode << 1) | 0x01); /* HDMI free run */ |
| 1713 | cp_write(sd, 0xf3, 0xdc); /* Low threshold to enter/exit free run mode */ | 1894 | cp_write(sd, 0xf3, 0xdc); /* Low threshold to enter/exit free run mode */ |
| 1714 | cp_write(sd, 0xf9, 0x23); /* STDI ch. 1 - LCVS change threshold - | 1895 | cp_write(sd, 0xf9, 0x23); /* STDI ch. 1 - LCVS change threshold - |
| 1715 | ADI recommended setting [REF_01 c. 2.3.3] */ | 1896 | ADI recommended setting [REF_01, c. 2.3.3] */ |
| 1716 | cp_write(sd, 0x45, 0x23); /* STDI ch. 2 - LCVS change threshold - | 1897 | cp_write(sd, 0x45, 0x23); /* STDI ch. 2 - LCVS change threshold - |
| 1717 | ADI recommended setting [REF_01 c. 2.3.3] */ | 1898 | ADI recommended setting [REF_01, c. 2.3.3] */ |
| 1718 | cp_write(sd, 0xc9, 0x2d); /* use prim_mode and vid_std as free run resolution | 1899 | cp_write(sd, 0xc9, 0x2d); /* use prim_mode and vid_std as free run resolution |
| 1719 | for digital formats */ | 1900 | for digital formats */ |
| 1720 | 1901 | ||
| @@ -1724,11 +1905,6 @@ static int adv7604_core_init(struct v4l2_subdev *sd) | |||
| 1724 | afe_write(sd, 0x02, pdata->ain_sel); /* Select analog input muxing mode */ | 1905 | afe_write(sd, 0x02, pdata->ain_sel); /* Select analog input muxing mode */ |
| 1725 | io_write_and_or(sd, 0x30, ~(1 << 4), pdata->output_bus_lsb_to_msb << 4); | 1906 | io_write_and_or(sd, 0x30, ~(1 << 4), pdata->output_bus_lsb_to_msb << 4); |
| 1726 | 1907 | ||
| 1727 | state->prim_mode = pdata->prim_mode; | ||
| 1728 | select_input(sd, pdata->prim_mode); | ||
| 1729 | |||
| 1730 | enable_input(sd, pdata->prim_mode); | ||
| 1731 | |||
| 1732 | /* interrupts */ | 1908 | /* interrupts */ |
| 1733 | io_write(sd, 0x40, 0xc2); /* Configure INT1 */ | 1909 | io_write(sd, 0x40, 0xc2); /* Configure INT1 */ |
| 1734 | io_write(sd, 0x41, 0xd7); /* STDI irq for any change, disable INT2 */ | 1910 | io_write(sd, 0x41, 0xd7); /* STDI irq for any change, disable INT2 */ |
| @@ -1883,6 +2059,7 @@ static int adv7604_probe(struct i2c_client *client, | |||
| 1883 | v4l2_err(sd, "failed to create all i2c clients\n"); | 2059 | v4l2_err(sd, "failed to create all i2c clients\n"); |
| 1884 | goto err_i2c; | 2060 | goto err_i2c; |
| 1885 | } | 2061 | } |
| 2062 | state->restart_stdi_once = true; | ||
| 1886 | 2063 | ||
| 1887 | /* work queues */ | 2064 | /* work queues */ |
| 1888 | state->work_queues = create_singlethread_workqueue(client->name); | 2065 | state->work_queues = create_singlethread_workqueue(client->name); |
