openwrt/target/linux/d1/patches-6.1/0076-spi-spi-sun6i-Add-Allwinner-R329-support.patch

147 lines
4.9 KiB
Diff
Raw Normal View History

From ec8dfb455da3822451129257ab21e2f0d03a6ae3 Mon Sep 17 00:00:00 2001
From: Samuel Holland <samuel@sholland.org>
Date: Fri, 16 Jul 2021 21:46:31 -0500
Subject: [PATCH 076/117] spi: spi-sun6i: Add Allwinner R329 support
Signed-off-by: Samuel Holland <samuel@sholland.org>
---
drivers/spi/spi-sun6i.c | 78 ++++++++++++++++++++++++++---------------
1 file changed, 49 insertions(+), 29 deletions(-)
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -30,6 +30,7 @@
#define SUN6I_GBL_CTL_REG 0x04
#define SUN6I_GBL_CTL_BUS_ENABLE BIT(0)
#define SUN6I_GBL_CTL_MASTER BIT(1)
+#define SUN6I_GBL_CTL_SAMPLE_MODE BIT(2)
#define SUN6I_GBL_CTL_TP BIT(7)
#define SUN6I_GBL_CTL_RST BIT(31)
@@ -87,6 +88,8 @@
struct sun6i_spi_quirks {
unsigned long fifo_depth;
+ bool has_divider : 1;
+ bool has_new_sample_mode : 1;
};
struct sun6i_spi {
@@ -362,38 +365,44 @@ static int sun6i_spi_transfer_one(struct
sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
/* Ensure that we have a parent clock fast enough */
- mclk_rate = clk_get_rate(sspi->mclk);
- if (mclk_rate < (2 * tfr->speed_hz)) {
- clk_set_rate(sspi->mclk, 2 * tfr->speed_hz);
+ if (sspi->quirks->has_divider) {
mclk_rate = clk_get_rate(sspi->mclk);
- }
+ if (mclk_rate < (2 * tfr->speed_hz)) {
+ clk_set_rate(sspi->mclk, 2 * tfr->speed_hz);
+ mclk_rate = clk_get_rate(sspi->mclk);
+ }
- /*
- * Setup clock divider.
- *
- * We have two choices there. Either we can use the clock
- * divide rate 1, which is calculated thanks to this formula:
- * SPI_CLK = MOD_CLK / (2 ^ cdr)
- * Or we can use CDR2, which is calculated with the formula:
- * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
- * Wether we use the former or the latter is set through the
- * DRS bit.
- *
- * First try CDR2, and if we can't reach the expected
- * frequency, fall back to CDR1.
- */
- div_cdr1 = DIV_ROUND_UP(mclk_rate, tfr->speed_hz);
- div_cdr2 = DIV_ROUND_UP(div_cdr1, 2);
- if (div_cdr2 <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) {
- reg = SUN6I_CLK_CTL_CDR2(div_cdr2 - 1) | SUN6I_CLK_CTL_DRS;
- tfr->effective_speed_hz = mclk_rate / (2 * div_cdr2);
+ /*
+ * Setup clock divider.
+ *
+ * We have two choices there. Either we can use the clock
+ * divide rate 1, which is calculated thanks to this formula:
+ * SPI_CLK = MOD_CLK / (2 ^ cdr)
+ * Or we can use CDR2, which is calculated with the formula:
+ * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
+ * Wether we use the former or the latter is set through the
+ * DRS bit.
+ *
+ * First try CDR2, and if we can't reach the expected
+ * frequency, fall back to CDR1.
+ */
+ div_cdr1 = DIV_ROUND_UP(mclk_rate, tfr->speed_hz);
+ div_cdr2 = DIV_ROUND_UP(div_cdr1, 2);
+ if (div_cdr2 <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) {
+ reg = SUN6I_CLK_CTL_CDR2(div_cdr2 - 1) | SUN6I_CLK_CTL_DRS;
+ tfr->effective_speed_hz = mclk_rate / (2 * div_cdr2);
+ } else {
+ div = min(SUN6I_CLK_CTL_CDR1_MASK, order_base_2(div_cdr1));
+ reg = SUN6I_CLK_CTL_CDR1(div);
+ tfr->effective_speed_hz = mclk_rate / (1 << div);
+ }
+ sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg);
} else {
- div = min(SUN6I_CLK_CTL_CDR1_MASK, order_base_2(div_cdr1));
- reg = SUN6I_CLK_CTL_CDR1(div);
- tfr->effective_speed_hz = mclk_rate / (1 << div);
+ clk_set_rate(sspi->mclk, tfr->speed_hz);
+ mclk_rate = clk_get_rate(sspi->mclk);
+ tfr->effective_speed_hz = mclk_rate;
}
- sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg);
/* Finally enable the bus - doing so before might raise SCK to HIGH */
reg = sun6i_spi_read(sspi, SUN6I_GBL_CTL_REG);
reg |= SUN6I_GBL_CTL_BUS_ENABLE;
@@ -518,6 +527,7 @@ static int sun6i_spi_runtime_resume(stru
struct spi_master *master = dev_get_drvdata(dev);
struct sun6i_spi *sspi = spi_master_get_devdata(master);
int ret;
+ u32 reg;
ret = clk_prepare_enable(sspi->hclk);
if (ret) {
@@ -537,8 +547,10 @@ static int sun6i_spi_runtime_resume(stru
goto err2;
}
- sun6i_spi_write(sspi, SUN6I_GBL_CTL_REG,
- SUN6I_GBL_CTL_MASTER | SUN6I_GBL_CTL_TP);
+ reg = SUN6I_GBL_CTL_MASTER | SUN6I_GBL_CTL_TP;
+ if (sspi->quirks->has_new_sample_mode)
+ reg |= SUN6I_GBL_CTL_SAMPLE_MODE;
+ sun6i_spi_write(sspi, SUN6I_GBL_CTL_REG, reg);
return 0;
@@ -729,15 +741,23 @@ static int sun6i_spi_remove(struct platf
static const struct sun6i_spi_quirks sun6i_a31_spi_quirks = {
.fifo_depth = SUN6I_FIFO_DEPTH,
+ .has_divider = true,
};
static const struct sun6i_spi_quirks sun8i_h3_spi_quirks = {
.fifo_depth = SUN8I_FIFO_DEPTH,
+ .has_divider = true,
+};
+
+static const struct sun6i_spi_quirks sun50i_r329_spi_quirks = {
+ .fifo_depth = SUN8I_FIFO_DEPTH,
+ .has_new_sample_mode = true,
};
static const struct of_device_id sun6i_spi_match[] = {
{ .compatible = "allwinner,sun6i-a31-spi", .data = &sun6i_a31_spi_quirks },
{ .compatible = "allwinner,sun8i-h3-spi", .data = &sun8i_h3_spi_quirks },
+ { .compatible = "allwinner,sun50i-r329-spi", .data = &sun50i_r329_spi_quirks },
{}
};
MODULE_DEVICE_TABLE(of, sun6i_spi_match);