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

mfd: rtsx: Add clock divider hook

Add callback function conv_clk_and_div_n to convert between SSC clock
and its divider N.
For rtl8411, the formula to calculate SSC clock divider N is different
with the other card reader models.

Signed-off-by: Wei WANG <wei_wang@realsil.com.cn>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>

authored by

Wei WANG and committed by
Samuel Ortiz
ab4e8f8b ef85e736

+31 -2
+13
drivers/mfd/rtl8411.c
··· 178 178 return card_exist; 179 179 } 180 180 181 + static int rtl8411_conv_clk_and_div_n(int input, int dir) 182 + { 183 + int output; 184 + 185 + if (dir == CLK_TO_DIV_N) 186 + output = input * 4 / 5 - 2; 187 + else 188 + output = (input + 2) * 5 / 4; 189 + 190 + return output; 191 + } 192 + 181 193 static const struct pcr_ops rtl8411_pcr_ops = { 182 194 .extra_init_hw = rtl8411_extra_init_hw, 183 195 .optimize_phy = NULL, ··· 201 189 .card_power_off = rtl8411_card_power_off, 202 190 .switch_output_voltage = rtl8411_switch_output_voltage, 203 191 .cd_deglitch = rtl8411_cd_deglitch, 192 + .conv_clk_and_div_n = rtl8411_conv_clk_and_div_n, 204 193 }; 205 194 206 195 /* SD Pull Control Enable:
+1
drivers/mfd/rts5209.c
··· 174 174 .card_power_off = rts5209_card_power_off, 175 175 .switch_output_voltage = rts5209_switch_output_voltage, 176 176 .cd_deglitch = NULL, 177 + .conv_clk_and_div_n = NULL, 177 178 }; 178 179 179 180 /* SD Pull Control Enable:
+1
drivers/mfd/rts5229.c
··· 144 144 .card_power_off = rts5229_card_power_off, 145 145 .switch_output_voltage = rts5229_switch_output_voltage, 146 146 .cd_deglitch = NULL, 147 + .conv_clk_and_div_n = NULL, 147 148 }; 148 149 149 150 /* SD Pull Control Enable:
+12 -2
drivers/mfd/rtsx_pcr.c
··· 630 630 if (clk == pcr->cur_clock) 631 631 return 0; 632 632 633 - N = (u8)(clk - 2); 633 + if (pcr->ops->conv_clk_and_div_n) 634 + N = (u8)pcr->ops->conv_clk_and_div_n(clk, CLK_TO_DIV_N); 635 + else 636 + N = (u8)(clk - 2); 634 637 if ((clk <= 2) || (N > max_N)) 635 638 return -EINVAL; 636 639 ··· 644 641 /* Make sure that the SSC clock div_n is equal or greater than min_N */ 645 642 div = CLK_DIV_1; 646 643 while ((N < min_N) && (div < max_div)) { 647 - N = (N + 2) * 2 - 2; 644 + if (pcr->ops->conv_clk_and_div_n) { 645 + int dbl_clk = pcr->ops->conv_clk_and_div_n(N, 646 + DIV_N_TO_CLK) * 2; 647 + N = (u8)pcr->ops->conv_clk_and_div_n(dbl_clk, 648 + CLK_TO_DIV_N); 649 + } else { 650 + N = (N + 2) * 2 - 2; 651 + } 648 652 div++; 649 653 } 650 654 dev_dbg(&(pcr->pci->dev), "N = %d, div = %d\n", N, div);
+3
include/linux/mfd/rtsx_common.h
··· 38 38 #define RTSX_SD_CARD 0 39 39 #define RTSX_MS_CARD 1 40 40 41 + #define CLK_TO_DIV_N 0 42 + #define DIV_N_TO_CLK 1 43 + 41 44 struct platform_device; 42 45 43 46 struct rtsx_slot {
+1
include/linux/mfd/rtsx_pci.h
··· 704 704 int (*switch_output_voltage)(struct rtsx_pcr *pcr, 705 705 u8 voltage); 706 706 unsigned int (*cd_deglitch)(struct rtsx_pcr *pcr); 707 + int (*conv_clk_and_div_n)(int clk, int dir); 707 708 }; 708 709 709 710 enum PDEV_STAT {PDEV_STAT_IDLE, PDEV_STAT_RUN};