d1: add new target
[openwrt/staging/nbd.git] / target / linux / d1 / patches-6.1 / 0076-spi-spi-sun6i-Add-Allwinner-R329-support.patch
1 From ec8dfb455da3822451129257ab21e2f0d03a6ae3 Mon Sep 17 00:00:00 2001
2 From: Samuel Holland <samuel@sholland.org>
3 Date: Fri, 16 Jul 2021 21:46:31 -0500
4 Subject: [PATCH 076/117] spi: spi-sun6i: Add Allwinner R329 support
5
6 Signed-off-by: Samuel Holland <samuel@sholland.org>
7 ---
8 drivers/spi/spi-sun6i.c | 78 ++++++++++++++++++++++++++---------------
9 1 file changed, 49 insertions(+), 29 deletions(-)
10
11 --- a/drivers/spi/spi-sun6i.c
12 +++ b/drivers/spi/spi-sun6i.c
13 @@ -30,6 +30,7 @@
14 #define SUN6I_GBL_CTL_REG 0x04
15 #define SUN6I_GBL_CTL_BUS_ENABLE BIT(0)
16 #define SUN6I_GBL_CTL_MASTER BIT(1)
17 +#define SUN6I_GBL_CTL_SAMPLE_MODE BIT(2)
18 #define SUN6I_GBL_CTL_TP BIT(7)
19 #define SUN6I_GBL_CTL_RST BIT(31)
20
21 @@ -87,6 +88,8 @@
22
23 struct sun6i_spi_quirks {
24 unsigned long fifo_depth;
25 + bool has_divider : 1;
26 + bool has_new_sample_mode : 1;
27 };
28
29 struct sun6i_spi {
30 @@ -362,38 +365,44 @@ static int sun6i_spi_transfer_one(struct
31 sun6i_spi_write(sspi, SUN6I_TFR_CTL_REG, reg);
32
33 /* Ensure that we have a parent clock fast enough */
34 - mclk_rate = clk_get_rate(sspi->mclk);
35 - if (mclk_rate < (2 * tfr->speed_hz)) {
36 - clk_set_rate(sspi->mclk, 2 * tfr->speed_hz);
37 + if (sspi->quirks->has_divider) {
38 mclk_rate = clk_get_rate(sspi->mclk);
39 - }
40 + if (mclk_rate < (2 * tfr->speed_hz)) {
41 + clk_set_rate(sspi->mclk, 2 * tfr->speed_hz);
42 + mclk_rate = clk_get_rate(sspi->mclk);
43 + }
44
45 - /*
46 - * Setup clock divider.
47 - *
48 - * We have two choices there. Either we can use the clock
49 - * divide rate 1, which is calculated thanks to this formula:
50 - * SPI_CLK = MOD_CLK / (2 ^ cdr)
51 - * Or we can use CDR2, which is calculated with the formula:
52 - * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
53 - * Wether we use the former or the latter is set through the
54 - * DRS bit.
55 - *
56 - * First try CDR2, and if we can't reach the expected
57 - * frequency, fall back to CDR1.
58 - */
59 - div_cdr1 = DIV_ROUND_UP(mclk_rate, tfr->speed_hz);
60 - div_cdr2 = DIV_ROUND_UP(div_cdr1, 2);
61 - if (div_cdr2 <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) {
62 - reg = SUN6I_CLK_CTL_CDR2(div_cdr2 - 1) | SUN6I_CLK_CTL_DRS;
63 - tfr->effective_speed_hz = mclk_rate / (2 * div_cdr2);
64 + /*
65 + * Setup clock divider.
66 + *
67 + * We have two choices there. Either we can use the clock
68 + * divide rate 1, which is calculated thanks to this formula:
69 + * SPI_CLK = MOD_CLK / (2 ^ cdr)
70 + * Or we can use CDR2, which is calculated with the formula:
71 + * SPI_CLK = MOD_CLK / (2 * (cdr + 1))
72 + * Wether we use the former or the latter is set through the
73 + * DRS bit.
74 + *
75 + * First try CDR2, and if we can't reach the expected
76 + * frequency, fall back to CDR1.
77 + */
78 + div_cdr1 = DIV_ROUND_UP(mclk_rate, tfr->speed_hz);
79 + div_cdr2 = DIV_ROUND_UP(div_cdr1, 2);
80 + if (div_cdr2 <= (SUN6I_CLK_CTL_CDR2_MASK + 1)) {
81 + reg = SUN6I_CLK_CTL_CDR2(div_cdr2 - 1) | SUN6I_CLK_CTL_DRS;
82 + tfr->effective_speed_hz = mclk_rate / (2 * div_cdr2);
83 + } else {
84 + div = min(SUN6I_CLK_CTL_CDR1_MASK, order_base_2(div_cdr1));
85 + reg = SUN6I_CLK_CTL_CDR1(div);
86 + tfr->effective_speed_hz = mclk_rate / (1 << div);
87 + }
88 + sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg);
89 } else {
90 - div = min(SUN6I_CLK_CTL_CDR1_MASK, order_base_2(div_cdr1));
91 - reg = SUN6I_CLK_CTL_CDR1(div);
92 - tfr->effective_speed_hz = mclk_rate / (1 << div);
93 + clk_set_rate(sspi->mclk, tfr->speed_hz);
94 + mclk_rate = clk_get_rate(sspi->mclk);
95 + tfr->effective_speed_hz = mclk_rate;
96 }
97
98 - sun6i_spi_write(sspi, SUN6I_CLK_CTL_REG, reg);
99 /* Finally enable the bus - doing so before might raise SCK to HIGH */
100 reg = sun6i_spi_read(sspi, SUN6I_GBL_CTL_REG);
101 reg |= SUN6I_GBL_CTL_BUS_ENABLE;
102 @@ -518,6 +527,7 @@ static int sun6i_spi_runtime_resume(stru
103 struct spi_master *master = dev_get_drvdata(dev);
104 struct sun6i_spi *sspi = spi_master_get_devdata(master);
105 int ret;
106 + u32 reg;
107
108 ret = clk_prepare_enable(sspi->hclk);
109 if (ret) {
110 @@ -537,8 +547,10 @@ static int sun6i_spi_runtime_resume(stru
111 goto err2;
112 }
113
114 - sun6i_spi_write(sspi, SUN6I_GBL_CTL_REG,
115 - SUN6I_GBL_CTL_MASTER | SUN6I_GBL_CTL_TP);
116 + reg = SUN6I_GBL_CTL_MASTER | SUN6I_GBL_CTL_TP;
117 + if (sspi->quirks->has_new_sample_mode)
118 + reg |= SUN6I_GBL_CTL_SAMPLE_MODE;
119 + sun6i_spi_write(sspi, SUN6I_GBL_CTL_REG, reg);
120
121 return 0;
122
123 @@ -729,15 +741,23 @@ static int sun6i_spi_remove(struct platf
124
125 static const struct sun6i_spi_quirks sun6i_a31_spi_quirks = {
126 .fifo_depth = SUN6I_FIFO_DEPTH,
127 + .has_divider = true,
128 };
129
130 static const struct sun6i_spi_quirks sun8i_h3_spi_quirks = {
131 .fifo_depth = SUN8I_FIFO_DEPTH,
132 + .has_divider = true,
133 +};
134 +
135 +static const struct sun6i_spi_quirks sun50i_r329_spi_quirks = {
136 + .fifo_depth = SUN8I_FIFO_DEPTH,
137 + .has_new_sample_mode = true,
138 };
139
140 static const struct of_device_id sun6i_spi_match[] = {
141 { .compatible = "allwinner,sun6i-a31-spi", .data = &sun6i_a31_spi_quirks },
142 { .compatible = "allwinner,sun8i-h3-spi", .data = &sun8i_h3_spi_quirks },
143 + { .compatible = "allwinner,sun50i-r329-spi", .data = &sun50i_r329_spi_quirks },
144 {}
145 };
146 MODULE_DEVICE_TABLE(of, sun6i_spi_match);