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

spi: s3c64xx: support custom value of internal clock divider

Modern exynos SoCs such as Exynos Auto v9 have different internal clock
divider, for example "4". To support this internal value, this adds
clk_div of the s3c64xx_spi_port_config and assign "2" as the default
value to existing s3c64xx_spi_port_config.

Signed-off-by: Chanho Park <chanho61.park@samsung.com>
Reviewed-by: Andi Shyti <andi@etezian.org>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
Link: https://lore.kernel.org/r/20220629102304.65712-3-chanho61.park@samsung.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Chanho Park and committed by
Mark Brown
bfcd27dc ffb7bcd3

+20 -8
+20 -8
drivers/spi/spi-s3c64xx.c
··· 131 131 * @fifo_lvl_mask: Bit-mask for {TX|RX}_FIFO_LVL bits in SPI_STATUS register. 132 132 * @rx_lvl_offset: Bit offset of RX_FIFO_LVL bits in SPI_STATUS regiter. 133 133 * @tx_st_done: Bit offset of TX_DONE bit in SPI_STATUS regiter. 134 + * @clk_div: Internal clock divider 134 135 * @quirks: Bitmask of known quirks 135 136 * @high_speed: True, if the controller supports HIGH_SPEED_EN bit. 136 137 * @clk_from_cmu: True, if the controller does not include a clock mux and ··· 149 148 int rx_lvl_offset; 150 149 int tx_st_done; 151 150 int quirks; 151 + int clk_div; 152 152 bool high_speed; 153 153 bool clk_from_cmu; 154 154 bool clk_ioclk; ··· 622 620 void __iomem *regs = sdd->regs; 623 621 int ret; 624 622 u32 val; 623 + int div = sdd->port_conf->clk_div; 625 624 626 625 /* Disable Clock */ 627 626 if (!sdd->port_conf->clk_from_cmu) { ··· 671 668 writel(val, regs + S3C64XX_SPI_MODE_CFG); 672 669 673 670 if (sdd->port_conf->clk_from_cmu) { 674 - /* The src_clk clock is divided internally by 2 */ 675 - ret = clk_set_rate(sdd->src_clk, sdd->cur_speed * 2); 671 + ret = clk_set_rate(sdd->src_clk, sdd->cur_speed * div); 676 672 if (ret) 677 673 return ret; 678 - sdd->cur_speed = clk_get_rate(sdd->src_clk) / 2; 674 + sdd->cur_speed = clk_get_rate(sdd->src_clk) / div; 679 675 } else { 680 676 /* Configure Clock */ 681 677 val = readl(regs + S3C64XX_SPI_CLK_CFG); 682 678 val &= ~S3C64XX_SPI_PSR_MASK; 683 - val |= ((clk_get_rate(sdd->src_clk) / sdd->cur_speed / 2 - 1) 679 + val |= ((clk_get_rate(sdd->src_clk) / sdd->cur_speed / div - 1) 684 680 & S3C64XX_SPI_PSR_MASK); 685 681 writel(val, regs + S3C64XX_SPI_CLK_CFG); 686 682 ··· 873 871 struct s3c64xx_spi_csinfo *cs = spi->controller_data; 874 872 struct s3c64xx_spi_driver_data *sdd; 875 873 int err; 874 + int div; 876 875 877 876 sdd = spi_master_get_devdata(spi->master); 878 877 if (spi->dev.of_node) { ··· 892 889 893 890 pm_runtime_get_sync(&sdd->pdev->dev); 894 891 892 + div = sdd->port_conf->clk_div; 893 + 895 894 /* Check if we can provide the requested rate */ 896 895 if (!sdd->port_conf->clk_from_cmu) { 897 896 u32 psr, speed; 898 897 899 898 /* Max possible */ 900 - speed = clk_get_rate(sdd->src_clk) / 2 / (0 + 1); 899 + speed = clk_get_rate(sdd->src_clk) / div / (0 + 1); 901 900 902 901 if (spi->max_speed_hz > speed) 903 902 spi->max_speed_hz = speed; 904 903 905 - psr = clk_get_rate(sdd->src_clk) / 2 / spi->max_speed_hz - 1; 904 + psr = clk_get_rate(sdd->src_clk) / div / spi->max_speed_hz - 1; 906 905 psr &= S3C64XX_SPI_PSR_MASK; 907 906 if (psr == S3C64XX_SPI_PSR_MASK) 908 907 psr--; 909 908 910 - speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1); 909 + speed = clk_get_rate(sdd->src_clk) / div / (psr + 1); 911 910 if (spi->max_speed_hz < speed) { 912 911 if (psr+1 < S3C64XX_SPI_PSR_MASK) { 913 912 psr++; ··· 919 914 } 920 915 } 921 916 922 - speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1); 917 + speed = clk_get_rate(sdd->src_clk) / div / (psr + 1); 923 918 if (spi->max_speed_hz >= speed) { 924 919 spi->max_speed_hz = speed; 925 920 } else { ··· 1401 1396 .fifo_lvl_mask = { 0x7f }, 1402 1397 .rx_lvl_offset = 13, 1403 1398 .tx_st_done = 21, 1399 + .clk_div = 2, 1404 1400 .high_speed = true, 1405 1401 }; 1406 1402 ··· 1409 1403 .fifo_lvl_mask = { 0x7f, 0x7F }, 1410 1404 .rx_lvl_offset = 13, 1411 1405 .tx_st_done = 21, 1406 + .clk_div = 2, 1412 1407 }; 1413 1408 1414 1409 static const struct s3c64xx_spi_port_config s5pv210_spi_port_config = { 1415 1410 .fifo_lvl_mask = { 0x1ff, 0x7F }, 1416 1411 .rx_lvl_offset = 15, 1417 1412 .tx_st_done = 25, 1413 + .clk_div = 2, 1418 1414 .high_speed = true, 1419 1415 }; 1420 1416 ··· 1424 1416 .fifo_lvl_mask = { 0x1ff, 0x7F, 0x7F }, 1425 1417 .rx_lvl_offset = 15, 1426 1418 .tx_st_done = 25, 1419 + .clk_div = 2, 1427 1420 .high_speed = true, 1428 1421 .clk_from_cmu = true, 1429 1422 .quirks = S3C64XX_SPI_QUIRK_CS_AUTO, ··· 1434 1425 .fifo_lvl_mask = { 0x1ff, 0x7F, 0x7F, 0x7F, 0x7F, 0x1ff}, 1435 1426 .rx_lvl_offset = 15, 1436 1427 .tx_st_done = 25, 1428 + .clk_div = 2, 1437 1429 .high_speed = true, 1438 1430 .clk_from_cmu = true, 1439 1431 .quirks = S3C64XX_SPI_QUIRK_CS_AUTO, ··· 1444 1434 .fifo_lvl_mask = { 0x1ff, 0x7f, 0x7f, 0x7f, 0x7f, 0x1ff}, 1445 1435 .rx_lvl_offset = 15, 1446 1436 .tx_st_done = 25, 1437 + .clk_div = 2, 1447 1438 .high_speed = true, 1448 1439 .clk_from_cmu = true, 1449 1440 .clk_ioclk = true, ··· 1455 1444 .fifo_lvl_mask = { 0x7f, 0x7f, 0x7f, 0x7f, 0x7f}, 1456 1445 .rx_lvl_offset = 15, 1457 1446 .tx_st_done = 25, 1447 + .clk_div = 2, 1458 1448 .high_speed = true, 1459 1449 .clk_from_cmu = true, 1460 1450 .clk_ioclk = false,