Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

dpll: zl3073x: Cache all output properties in zl3073x_out

Expand the zl3073x_out structure to cache all output-related
hardware registers, including divisors, widths, embedded-sync
parameters and phase compensation.

Modify zl3073x_out_state_fetch() to read and populate all these
new fields at once, including zero-divisor checks. Refactor all
dpll "getter" functions in dpll.c to read from this new
cached state instead of performing direct register access.

Introduce a new function, zl3073x_out_state_set(), to handle
writing changes back to the hardware. This function compares the
provided state with the current cached state and writes *only* the
modified register values via a single mailbox sequence before
updating the local cache.

Refactor all dpll "setter" functions to modify a local copy of
the output state and then call zl3073x_out_state_set() to
commit the changes.

This change centralizes all output-related register I/O into
out.c, significantly reduces bus traffic, and simplifies the logic
in dpll.c.

Reviewed-by: Petr Oros <poros@redhat.com>
Tested-by: Prathosh Satish <Prathosh.Satish@microchip.com>
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
Link: https://patch.msgid.link/20251113074105.141379-6-ivecera@redhat.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Ivan Vecera and committed by
Jakub Kicinski
5fb9b0d4 5bc02b19

+193 -290
+90 -290
drivers/dpll/zl3073x/dpll.c
··· 770 770 struct zl3073x_dpll *zldpll = dpll_priv; 771 771 struct zl3073x_dev *zldev = zldpll->dev; 772 772 struct zl3073x_dpll_pin *pin = pin_priv; 773 - struct device *dev = zldev->dev; 774 - u32 esync_period, esync_width; 775 - u8 clock_type, synth; 776 - u8 out, output_mode; 777 - u32 output_div; 773 + const struct zl3073x_synth *synth; 774 + const struct zl3073x_out *out; 775 + u8 clock_type, out_id; 778 776 u32 synth_freq; 779 - int rc; 780 777 781 - out = zl3073x_output_pin_out_get(pin->id); 778 + out_id = zl3073x_output_pin_out_get(pin->id); 779 + out = zl3073x_out_state_get(zldev, out_id); 782 780 783 781 /* If N-division is enabled, esync is not supported. The register used 784 782 * for N-division is also used for the esync divider so both cannot 785 783 * be used. 786 784 */ 787 - switch (zl3073x_dev_out_signal_format_get(zldev, out)) { 785 + switch (zl3073x_out_signal_format_get(out)) { 788 786 case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV: 789 787 case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV_INV: 790 788 return -EOPNOTSUPP; ··· 790 792 break; 791 793 } 792 794 793 - guard(mutex)(&zldev->multiop_lock); 795 + /* Get attached synth frequency */ 796 + synth = zl3073x_synth_state_get(zldev, zl3073x_out_synth_get(out)); 797 + synth_freq = zl3073x_synth_freq_get(synth); 794 798 795 - /* Read output configuration into mailbox */ 796 - rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD, 797 - ZL_REG_OUTPUT_MB_MASK, BIT(out)); 798 - if (rc) 799 - return rc; 800 - 801 - /* Read output mode */ 802 - rc = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_MODE, &output_mode); 803 - if (rc) 804 - return rc; 805 - 806 - /* Read output divisor */ 807 - rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_DIV, &output_div); 808 - if (rc) 809 - return rc; 810 - 811 - /* Check output divisor for zero */ 812 - if (!output_div) { 813 - dev_err(dev, "Zero divisor for OUTPUT%u got from device\n", 814 - out); 815 - return -EINVAL; 816 - } 817 - 818 - /* Get synth attached to output pin */ 819 - synth = zl3073x_dev_out_synth_get(zldev, out); 820 - 821 - /* Get synth frequency */ 822 - synth_freq = zl3073x_dev_synth_freq_get(zldev, synth); 823 - 824 - clock_type = FIELD_GET(ZL_OUTPUT_MODE_CLOCK_TYPE, output_mode); 799 + clock_type = FIELD_GET(ZL_OUTPUT_MODE_CLOCK_TYPE, out->mode); 825 800 if (clock_type != ZL_OUTPUT_MODE_CLOCK_TYPE_ESYNC) { 826 801 /* No need to read esync data if it is not enabled */ 827 802 esync->freq = 0; ··· 803 832 goto finish; 804 833 } 805 834 806 - /* Read esync period */ 807 - rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD, &esync_period); 808 - if (rc) 809 - return rc; 810 - 811 - /* Check esync divisor for zero */ 812 - if (!esync_period) { 813 - dev_err(dev, "Zero esync divisor for OUTPUT%u got from device\n", 814 - out); 815 - return -EINVAL; 816 - } 817 - 818 - /* Get esync pulse width in units of half synth cycles */ 819 - rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_ESYNC_WIDTH, &esync_width); 820 - if (rc) 821 - return rc; 822 - 823 835 /* Compute esync frequency */ 824 - esync->freq = synth_freq / output_div / esync_period; 836 + esync->freq = synth_freq / out->div / out->esync_n_period; 825 837 826 838 /* By comparing the esync_pulse_width to the half of the pulse width 827 839 * the esync pulse percentage can be determined. 828 840 * Note that half pulse width is in units of half synth cycles, which 829 841 * is why it reduces down to be output_div. 830 842 */ 831 - esync->pulse = (50 * esync_width) / output_div; 843 + esync->pulse = (50 * out->esync_n_width) / out->div; 832 844 833 845 finish: 834 846 /* Set supported esync ranges if the pin supports esync control and 835 847 * if the output frequency is > 1 Hz. 836 848 */ 837 - if (pin->esync_control && (synth_freq / output_div) > 1) { 849 + if (pin->esync_control && (synth_freq / out->div) > 1) { 838 850 esync->range = esync_freq_ranges; 839 851 esync->range_num = ARRAY_SIZE(esync_freq_ranges); 840 852 } else { ··· 835 881 void *dpll_priv, u64 freq, 836 882 struct netlink_ext_ack *extack) 837 883 { 838 - u32 esync_period, esync_width, output_div; 839 884 struct zl3073x_dpll *zldpll = dpll_priv; 840 885 struct zl3073x_dev *zldev = zldpll->dev; 841 886 struct zl3073x_dpll_pin *pin = pin_priv; 842 - u8 clock_type, out, output_mode, synth; 887 + const struct zl3073x_synth *synth; 888 + struct zl3073x_out out; 889 + u8 clock_type, out_id; 843 890 u32 synth_freq; 844 - int rc; 845 891 846 - out = zl3073x_output_pin_out_get(pin->id); 892 + out_id = zl3073x_output_pin_out_get(pin->id); 893 + out = *zl3073x_out_state_get(zldev, out_id); 847 894 848 895 /* If N-division is enabled, esync is not supported. The register used 849 896 * for N-division is also used for the esync divider so both cannot 850 897 * be used. 851 898 */ 852 - switch (zl3073x_dev_out_signal_format_get(zldev, out)) { 899 + switch (zl3073x_out_signal_format_get(&out)) { 853 900 case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV: 854 901 case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV_INV: 855 902 return -EOPNOTSUPP; 856 903 default: 857 904 break; 858 905 } 859 - 860 - guard(mutex)(&zldev->multiop_lock); 861 - 862 - /* Read output configuration into mailbox */ 863 - rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD, 864 - ZL_REG_OUTPUT_MB_MASK, BIT(out)); 865 - if (rc) 866 - return rc; 867 - 868 - /* Read output mode */ 869 - rc = zl3073x_read_u8(zldev, ZL_REG_OUTPUT_MODE, &output_mode); 870 - if (rc) 871 - return rc; 872 906 873 907 /* Select clock type */ 874 908 if (freq) ··· 865 923 clock_type = ZL_OUTPUT_MODE_CLOCK_TYPE_NORMAL; 866 924 867 925 /* Update clock type in output mode */ 868 - output_mode &= ~ZL_OUTPUT_MODE_CLOCK_TYPE; 869 - output_mode |= FIELD_PREP(ZL_OUTPUT_MODE_CLOCK_TYPE, clock_type); 870 - rc = zl3073x_write_u8(zldev, ZL_REG_OUTPUT_MODE, output_mode); 871 - if (rc) 872 - return rc; 926 + out.mode &= ~ZL_OUTPUT_MODE_CLOCK_TYPE; 927 + out.mode |= FIELD_PREP(ZL_OUTPUT_MODE_CLOCK_TYPE, clock_type); 873 928 874 929 /* If esync is being disabled just write mailbox and finish */ 875 930 if (!freq) 876 931 goto write_mailbox; 877 932 878 - /* Get synth attached to output pin */ 879 - synth = zl3073x_dev_out_synth_get(zldev, out); 880 - 881 - /* Get synth frequency */ 882 - synth_freq = zl3073x_dev_synth_freq_get(zldev, synth); 883 - 884 - rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_DIV, &output_div); 885 - if (rc) 886 - return rc; 887 - 888 - /* Check output divisor for zero */ 889 - if (!output_div) { 890 - dev_err(zldev->dev, 891 - "Zero divisor for OUTPUT%u got from device\n", out); 892 - return -EINVAL; 893 - } 933 + /* Get attached synth frequency */ 934 + synth = zl3073x_synth_state_get(zldev, zl3073x_out_synth_get(&out)); 935 + synth_freq = zl3073x_synth_freq_get(synth); 894 936 895 937 /* Compute and update esync period */ 896 - esync_period = synth_freq / (u32)freq / output_div; 897 - rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD, esync_period); 898 - if (rc) 899 - return rc; 938 + out.esync_n_period = synth_freq / (u32)freq / out.div; 900 939 901 940 /* Half of the period in units of 1/2 synth cycle can be represented by 902 941 * the output_div. To get the supported esync pulse width of 25% of the ··· 885 962 * assumes that output_div is even, otherwise some resolution will be 886 963 * lost. 887 964 */ 888 - esync_width = output_div / 2; 889 - rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_ESYNC_WIDTH, esync_width); 890 - if (rc) 891 - return rc; 965 + out.esync_n_width = out.div / 2; 892 966 893 967 write_mailbox: 894 968 /* Commit output configuration */ 895 - return zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_WR, 896 - ZL_REG_OUTPUT_MB_MASK, BIT(out)); 969 + return zl3073x_out_state_set(zldev, out_id, &out); 897 970 } 898 971 899 972 static int ··· 902 983 struct zl3073x_dpll *zldpll = dpll_priv; 903 984 struct zl3073x_dev *zldev = zldpll->dev; 904 985 struct zl3073x_dpll_pin *pin = pin_priv; 905 - struct device *dev = zldev->dev; 906 - u8 out, signal_format, synth; 907 - u32 output_div, synth_freq; 908 - int rc; 986 + const struct zl3073x_synth *synth; 987 + const struct zl3073x_out *out; 988 + u32 synth_freq; 989 + u8 out_id; 909 990 910 - out = zl3073x_output_pin_out_get(pin->id); 911 - synth = zl3073x_dev_out_synth_get(zldev, out); 912 - synth_freq = zl3073x_dev_synth_freq_get(zldev, synth); 991 + out_id = zl3073x_output_pin_out_get(pin->id); 992 + out = zl3073x_out_state_get(zldev, out_id); 913 993 914 - guard(mutex)(&zldev->multiop_lock); 994 + /* Get attached synth frequency */ 995 + synth = zl3073x_synth_state_get(zldev, zl3073x_out_synth_get(out)); 996 + synth_freq = zl3073x_synth_freq_get(synth); 915 997 916 - /* Read output configuration into mailbox */ 917 - rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD, 918 - ZL_REG_OUTPUT_MB_MASK, BIT(out)); 919 - if (rc) 920 - return rc; 921 - 922 - rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_DIV, &output_div); 923 - if (rc) 924 - return rc; 925 - 926 - /* Check output divisor for zero */ 927 - if (!output_div) { 928 - dev_err(dev, "Zero divisor for output %u got from device\n", 929 - out); 930 - return -EINVAL; 931 - } 932 - 933 - /* Read used signal format for the given output */ 934 - signal_format = zl3073x_dev_out_signal_format_get(zldev, out); 935 - 936 - switch (signal_format) { 998 + switch (zl3073x_out_signal_format_get(out)) { 937 999 case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV: 938 1000 case ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV_INV: 939 1001 /* In case of divided format we have to distiguish between 940 1002 * given output pin type. 1003 + * 1004 + * For P-pin the resulting frequency is computed as simple 1005 + * division of synth frequency and output divisor. 1006 + * 1007 + * For N-pin we have to divide additionally by divisor stored 1008 + * in esync_n_period output mailbox register that is used as 1009 + * N-pin divisor for these modes. 941 1010 */ 942 - if (zl3073x_dpll_is_p_pin(pin)) { 943 - /* For P-pin the resulting frequency is computed as 944 - * simple division of synth frequency and output 945 - * divisor. 946 - */ 947 - *frequency = synth_freq / output_div; 948 - } else { 949 - /* For N-pin we have to divide additionally by 950 - * divisor stored in esync_period output mailbox 951 - * register that is used as N-pin divisor for these 952 - * modes. 953 - */ 954 - u32 ndiv; 1011 + *frequency = synth_freq / out->div; 955 1012 956 - rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD, 957 - &ndiv); 958 - if (rc) 959 - return rc; 1013 + if (!zl3073x_dpll_is_p_pin(pin)) 1014 + *frequency = (u32)*frequency / out->esync_n_period; 960 1015 961 - /* Check N-pin divisor for zero */ 962 - if (!ndiv) { 963 - dev_err(dev, 964 - "Zero N-pin divisor for output %u got from device\n", 965 - out); 966 - return -EINVAL; 967 - } 968 - 969 - /* Compute final divisor for N-pin */ 970 - *frequency = synth_freq / output_div / ndiv; 971 - } 972 1016 break; 973 1017 default: 974 1018 /* In other modes the resulting frequency is computed as 975 1019 * division of synth frequency and output divisor. 976 1020 */ 977 - *frequency = synth_freq / output_div; 1021 + *frequency = synth_freq / out->div; 978 1022 break; 979 1023 } 980 1024 981 - return rc; 1025 + return 0; 982 1026 } 983 1027 984 1028 static int ··· 954 1072 struct zl3073x_dpll *zldpll = dpll_priv; 955 1073 struct zl3073x_dev *zldev = zldpll->dev; 956 1074 struct zl3073x_dpll_pin *pin = pin_priv; 957 - struct device *dev = zldev->dev; 958 - u32 output_n_freq, output_p_freq; 959 - u8 out, signal_format, synth; 960 - u32 cur_div, new_div, ndiv; 961 - u32 synth_freq; 962 - int rc; 1075 + const struct zl3073x_synth *synth; 1076 + u8 out_id, signal_format; 1077 + u32 new_div, synth_freq; 1078 + struct zl3073x_out out; 963 1079 964 - out = zl3073x_output_pin_out_get(pin->id); 965 - synth = zl3073x_dev_out_synth_get(zldev, out); 966 - synth_freq = zl3073x_dev_synth_freq_get(zldev, synth); 1080 + out_id = zl3073x_output_pin_out_get(pin->id); 1081 + out = *zl3073x_out_state_get(zldev, out_id); 1082 + 1083 + /* Get attached synth frequency and compute new divisor */ 1084 + synth = zl3073x_synth_state_get(zldev, zl3073x_out_synth_get(&out)); 1085 + synth_freq = zl3073x_synth_freq_get(synth); 967 1086 new_div = synth_freq / (u32)frequency; 968 1087 969 1088 /* Get used signal format for the given output */ 970 - signal_format = zl3073x_dev_out_signal_format_get(zldev, out); 971 - 972 - guard(mutex)(&zldev->multiop_lock); 973 - 974 - /* Load output configuration */ 975 - rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD, 976 - ZL_REG_OUTPUT_MB_MASK, BIT(out)); 977 - if (rc) 978 - return rc; 1089 + signal_format = zl3073x_out_signal_format_get(&out); 979 1090 980 1091 /* Check signal format */ 981 1092 if (signal_format != ZL_OUTPUT_MODE_SIGNAL_FORMAT_2_NDIV && ··· 976 1101 /* For non N-divided signal formats the frequency is computed 977 1102 * as division of synth frequency and output divisor. 978 1103 */ 979 - rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_DIV, new_div); 980 - if (rc) 981 - return rc; 1104 + out.div = new_div; 982 1105 983 1106 /* For 50/50 duty cycle the divisor is equal to width */ 984 - rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_WIDTH, new_div); 985 - if (rc) 986 - return rc; 1107 + out.width = new_div; 987 1108 988 1109 /* Commit output configuration */ 989 - return zl3073x_mb_op(zldev, 990 - ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_WR, 991 - ZL_REG_OUTPUT_MB_MASK, BIT(out)); 1110 + return zl3073x_out_state_set(zldev, out_id, &out); 992 1111 } 993 - 994 - /* For N-divided signal format get current divisor */ 995 - rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_DIV, &cur_div); 996 - if (rc) 997 - return rc; 998 - 999 - /* Check output divisor for zero */ 1000 - if (!cur_div) { 1001 - dev_err(dev, "Zero divisor for output %u got from device\n", 1002 - out); 1003 - return -EINVAL; 1004 - } 1005 - 1006 - /* Get N-pin divisor (shares the same register with esync */ 1007 - rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD, &ndiv); 1008 - if (rc) 1009 - return rc; 1010 - 1011 - /* Check N-pin divisor for zero */ 1012 - if (!ndiv) { 1013 - dev_err(dev, 1014 - "Zero N-pin divisor for output %u got from device\n", 1015 - out); 1016 - return -EINVAL; 1017 - } 1018 - 1019 - /* Compute current output frequency for P-pin */ 1020 - output_p_freq = synth_freq / cur_div; 1021 - 1022 - /* Compute current N-pin frequency */ 1023 - output_n_freq = output_p_freq / ndiv; 1024 1112 1025 1113 if (zl3073x_dpll_is_p_pin(pin)) { 1026 1114 /* We are going to change output frequency for P-pin but 1027 1115 * if the requested frequency is less than current N-pin 1028 1116 * frequency then indicate a failure as we are not able 1029 1117 * to compute N-pin divisor to keep its frequency unchanged. 1118 + * 1119 + * Update divisor for N-pin to keep N-pin frequency. 1030 1120 */ 1031 - if (frequency <= output_n_freq) 1121 + out.esync_n_period = (out.esync_n_period * out.div) / new_div; 1122 + if (!out.esync_n_period) 1032 1123 return -EINVAL; 1033 1124 1034 1125 /* Update the output divisor */ 1035 - rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_DIV, new_div); 1036 - if (rc) 1037 - return rc; 1126 + out.div = new_div; 1038 1127 1039 1128 /* For 50/50 duty cycle the divisor is equal to width */ 1040 - rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_WIDTH, new_div); 1041 - if (rc) 1042 - return rc; 1043 - 1044 - /* Compute new divisor for N-pin */ 1045 - ndiv = (u32)frequency / output_n_freq; 1129 + out.width = out.div; 1046 1130 } else { 1047 1131 /* We are going to change frequency of N-pin but if 1048 1132 * the requested freq is greater or equal than freq of P-pin 1049 1133 * in the output pair we cannot compute divisor for the N-pin. 1050 1134 * In this case indicate a failure. 1135 + * 1136 + * Update divisor for N-pin 1051 1137 */ 1052 - if (output_p_freq <= frequency) 1138 + out.esync_n_period = div64_u64(synth_freq, frequency * out.div); 1139 + if (!out.esync_n_period) 1053 1140 return -EINVAL; 1054 - 1055 - /* Compute new divisor for N-pin */ 1056 - ndiv = output_p_freq / (u32)frequency; 1057 1141 } 1058 1142 1059 - /* Update divisor for the N-pin */ 1060 - rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD, ndiv); 1061 - if (rc) 1062 - return rc; 1063 - 1064 1143 /* For 50/50 duty cycle the divisor is equal to width */ 1065 - rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_ESYNC_WIDTH, ndiv); 1066 - if (rc) 1067 - return rc; 1144 + out.esync_n_width = out.esync_n_period; 1068 1145 1069 1146 /* Commit output configuration */ 1070 - return zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_WR, 1071 - ZL_REG_OUTPUT_MB_MASK, BIT(out)); 1147 + return zl3073x_out_state_set(zldev, out_id, &out); 1072 1148 } 1073 1149 1074 1150 static int ··· 1033 1207 struct zl3073x_dpll *zldpll = dpll_priv; 1034 1208 struct zl3073x_dev *zldev = zldpll->dev; 1035 1209 struct zl3073x_dpll_pin *pin = pin_priv; 1036 - s32 phase_comp; 1037 - u8 out; 1038 - int rc; 1210 + const struct zl3073x_out *out; 1211 + u8 out_id; 1039 1212 1040 - guard(mutex)(&zldev->multiop_lock); 1041 - 1042 - /* Read output configuration */ 1043 - out = zl3073x_output_pin_out_get(pin->id); 1044 - rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD, 1045 - ZL_REG_OUTPUT_MB_MASK, BIT(out)); 1046 - if (rc) 1047 - return rc; 1048 - 1049 - /* Read current output phase compensation */ 1050 - rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_PHASE_COMP, &phase_comp); 1051 - if (rc) 1052 - return rc; 1213 + out_id = zl3073x_output_pin_out_get(pin->id); 1214 + out = zl3073x_out_state_get(zldev, out_id); 1053 1215 1054 1216 /* Convert value to ps and reverse two's complement negation applied 1055 1217 * during 'set' 1056 1218 */ 1057 - *phase_adjust = -phase_comp * pin->phase_gran; 1219 + *phase_adjust = -out->phase_comp * pin->phase_gran; 1058 1220 1059 - return rc; 1221 + return 0; 1060 1222 } 1061 1223 1062 1224 static int ··· 1058 1244 struct zl3073x_dpll *zldpll = dpll_priv; 1059 1245 struct zl3073x_dev *zldev = zldpll->dev; 1060 1246 struct zl3073x_dpll_pin *pin = pin_priv; 1061 - u8 out; 1062 - int rc; 1247 + struct zl3073x_out out; 1248 + u8 out_id; 1249 + 1250 + out_id = zl3073x_output_pin_out_get(pin->id); 1251 + out = *zl3073x_out_state_get(zldev, out_id); 1063 1252 1064 1253 /* The value in the register is stored as two's complement negation 1065 1254 * of requested value and expressed in half synth clock cycles. 1066 1255 */ 1067 - phase_adjust = -phase_adjust / pin->phase_gran; 1068 - 1069 - guard(mutex)(&zldev->multiop_lock); 1070 - 1071 - /* Read output configuration */ 1072 - out = zl3073x_output_pin_out_get(pin->id); 1073 - rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD, 1074 - ZL_REG_OUTPUT_MB_MASK, BIT(out)); 1075 - if (rc) 1076 - return rc; 1077 - 1078 - /* Write the requested value into the compensation register */ 1079 - rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_PHASE_COMP, phase_adjust); 1080 - if (rc) 1081 - return rc; 1256 + out.phase_comp = -phase_adjust / pin->phase_gran; 1082 1257 1083 1258 /* Update output configuration from mailbox */ 1084 - return zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_WR, 1085 - ZL_REG_OUTPUT_MB_MASK, BIT(out)); 1259 + return zl3073x_out_state_set(zldev, out_id, &out); 1086 1260 } 1087 1261 1088 1262 static int ··· 1482 1680 /* Output P&N pair shares single HW output */ 1483 1681 u8 out = zl3073x_output_pin_out_get(index); 1484 1682 1485 - name = "OUT"; 1486 - 1487 1683 /* Skip the pin if it is connected to different DPLL channel */ 1488 1684 if (zl3073x_dev_out_dpll_get(zldev, out) != zldpll->id) { 1489 1685 dev_dbg(zldev->dev, 1490 - "%s%u is driven by different DPLL\n", name, 1491 - out); 1686 + "OUT%u is driven by different DPLL\n", out); 1492 1687 1493 1688 return false; 1494 1689 } 1495 1690 1691 + name = "OUT"; 1496 1692 is_diff = zl3073x_dev_out_is_diff(zldev, out); 1497 1693 is_enabled = zl3073x_dev_output_pin_is_enabled(zldev, index); 1498 1694 }
+90
drivers/dpll/zl3073x/out.c
··· 50 50 dev_dbg(zldev->dev, "OUT%u has signal format 0x%02x\n", index, 51 51 zl3073x_out_signal_format_get(out)); 52 52 53 + /* Read output divisor */ 54 + rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_DIV, &out->div); 55 + if (rc) 56 + return rc; 57 + 58 + if (!out->div) { 59 + dev_err(zldev->dev, "Zero divisor for OUT%u got from device\n", 60 + index); 61 + return -EINVAL; 62 + } 63 + 64 + dev_dbg(zldev->dev, "OUT%u divisor: %u\n", index, out->div); 65 + 66 + /* Read output width */ 67 + rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_WIDTH, &out->width); 68 + if (rc) 69 + return rc; 70 + 71 + rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD, 72 + &out->esync_n_period); 73 + if (rc) 74 + return rc; 75 + 76 + if (!out->esync_n_period) { 77 + dev_err(zldev->dev, 78 + "Zero esync divisor for OUT%u got from device\n", 79 + index); 80 + return -EINVAL; 81 + } 82 + 83 + rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_ESYNC_WIDTH, 84 + &out->esync_n_width); 85 + if (rc) 86 + return rc; 87 + 88 + rc = zl3073x_read_u32(zldev, ZL_REG_OUTPUT_PHASE_COMP, 89 + &out->phase_comp); 90 + if (rc) 91 + return rc; 92 + 53 93 return rc; 54 94 } 55 95 ··· 104 64 u8 index) 105 65 { 106 66 return &zldev->out[index]; 67 + } 68 + 69 + int zl3073x_out_state_set(struct zl3073x_dev *zldev, u8 index, 70 + const struct zl3073x_out *out) 71 + { 72 + struct zl3073x_out *dout = &zldev->out[index]; 73 + int rc; 74 + 75 + guard(mutex)(&zldev->multiop_lock); 76 + 77 + /* Read output configuration into mailbox */ 78 + rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_RD, 79 + ZL_REG_OUTPUT_MB_MASK, BIT(index)); 80 + if (rc) 81 + return rc; 82 + 83 + /* Update mailbox with changed values */ 84 + if (dout->div != out->div) 85 + rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_DIV, out->div); 86 + if (!rc && dout->width != out->width) 87 + rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_WIDTH, out->width); 88 + if (!rc && dout->esync_n_period != out->esync_n_period) 89 + rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_ESYNC_PERIOD, 90 + out->esync_n_period); 91 + if (!rc && dout->esync_n_width != out->esync_n_width) 92 + rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_ESYNC_WIDTH, 93 + out->esync_n_width); 94 + if (!rc && dout->mode != out->mode) 95 + rc = zl3073x_write_u8(zldev, ZL_REG_OUTPUT_MODE, out->mode); 96 + if (!rc && dout->phase_comp != out->phase_comp) 97 + rc = zl3073x_write_u32(zldev, ZL_REG_OUTPUT_PHASE_COMP, 98 + out->phase_comp); 99 + if (rc) 100 + return rc; 101 + 102 + /* Commit output configuration */ 103 + rc = zl3073x_mb_op(zldev, ZL_REG_OUTPUT_MB_SEM, ZL_OUTPUT_MB_SEM_WR, 104 + ZL_REG_OUTPUT_MB_MASK, BIT(index)); 105 + if (rc) 106 + return rc; 107 + 108 + /* After successful commit store new state */ 109 + dout->div = out->div; 110 + dout->width = out->width; 111 + dout->esync_n_period = out->esync_n_period; 112 + dout->esync_n_width = out->esync_n_width; 113 + dout->mode = out->mode; 114 + dout->phase_comp = out->phase_comp; 115 + 116 + return 0; 107 117 }
+13
drivers/dpll/zl3073x/out.h
··· 12 12 13 13 /** 14 14 * struct zl3073x_out - output state 15 + * @div: output divisor 16 + * @width: output pulse width 17 + * @esync_n_period: embedded sync or n-pin period (for n-div formats) 18 + * @esync_n_width: embedded sync or n-pin pulse width 19 + * @phase_comp: phase compensation 15 20 * @ctrl: output control 16 21 * @mode: output mode 17 22 */ 18 23 struct zl3073x_out { 24 + u32 div; 25 + u32 width; 26 + u32 esync_n_period; 27 + u32 esync_n_width; 28 + s32 phase_comp; 19 29 u8 ctrl; 20 30 u8 mode; 21 31 }; ··· 33 23 int zl3073x_out_state_fetch(struct zl3073x_dev *zldev, u8 index); 34 24 const struct zl3073x_out *zl3073x_out_state_get(struct zl3073x_dev *zldev, 35 25 u8 index); 26 + 27 + int zl3073x_out_state_set(struct zl3073x_dev *zldev, u8 index, 28 + const struct zl3073x_out *out); 36 29 37 30 /** 38 31 * zl3073x_out_signal_format_get - get output signal format