Commit 4856cc7a972a7679cdbb33532ad932a3e865b18e
Committed by
Tom Rini
1 parent
391c40048b
Exists in
smarc_8mq_lf_v2020.04
and in
11 other branches
mpc8xxx_spi: implement real ->set_speed
Not all boards have the same CSB frequency, nor do every SPI slave necessarily support running at 16.7 MHz. So implement ->set_speed; that also allows using a smaller PM (i.e., 0) for slaves that do support a higher speed. Based on work by Klaus H. Sørensen. Cc: Klaus H. Sorensen <khso@prevas.dk> Signed-off-by: Rasmus Villemoes <rasmus.villemoes@prevas.dk>
Showing 1 changed file with 53 additions and 11 deletions Side-by-side Diff
drivers/spi/mpc8xxx_spi.c
... | ... | @@ -5,6 +5,7 @@ |
5 | 5 | */ |
6 | 6 | |
7 | 7 | #include <common.h> |
8 | +#include <clk.h> | |
8 | 9 | #include <dm.h> |
9 | 10 | #include <errno.h> |
10 | 11 | #include <malloc.h> |
... | ... | @@ -28,6 +29,7 @@ |
28 | 29 | |
29 | 30 | SPI_MODE_LEN_MASK = 0xf00000, |
30 | 31 | SPI_MODE_LEN_SHIFT = 20, |
32 | + SPI_MODE_PM_SHIFT = 16, | |
31 | 33 | SPI_MODE_PM_MASK = 0xf0000, |
32 | 34 | |
33 | 35 | SPI_COM_LST = BIT(31 - 9), |
34 | 36 | |
35 | 37 | |
36 | 38 | |
... | ... | @@ -37,24 +39,19 @@ |
37 | 39 | spi8xxx_t *spi; |
38 | 40 | struct gpio_desc gpios[16]; |
39 | 41 | int cs_count; |
42 | + ulong clk_rate; | |
40 | 43 | }; |
41 | 44 | |
42 | -static inline u32 to_prescale_mod(u32 val) | |
43 | -{ | |
44 | - return (min(val, (u32)15) << 16); | |
45 | -} | |
46 | - | |
47 | 45 | #define SPI_TIMEOUT 1000 |
48 | 46 | |
49 | 47 | static int mpc8xxx_spi_ofdata_to_platdata(struct udevice *dev) |
50 | 48 | { |
51 | 49 | struct mpc8xxx_priv *priv = dev_get_priv(dev); |
50 | + struct clk clk; | |
52 | 51 | int ret; |
53 | 52 | |
54 | 53 | priv->spi = (spi8xxx_t *)dev_read_addr(dev); |
55 | 54 | |
56 | - /* TODO(mario.six@gdsys.cc): Read clock and save the value */ | |
57 | - | |
58 | 55 | ret = gpio_request_list_by_name(dev, "gpios", priv->gpios, |
59 | 56 | ARRAY_SIZE(priv->gpios), GPIOD_IS_OUT | GPIOD_ACTIVE_LOW); |
60 | 57 | if (ret < 0) |
... | ... | @@ -62,6 +59,18 @@ |
62 | 59 | |
63 | 60 | priv->cs_count = ret; |
64 | 61 | |
62 | + ret = clk_get_by_index(dev, 0, &clk); | |
63 | + if (ret) { | |
64 | + dev_err(dev, "%s: clock not defined\n", __func__); | |
65 | + return ret; | |
66 | + } | |
67 | + | |
68 | + priv->clk_rate = clk_get_rate(&clk); | |
69 | + if (!priv->clk_rate) { | |
70 | + dev_err(dev, "%s: failed to get clock rate\n", __func__); | |
71 | + return -EINVAL; | |
72 | + } | |
73 | + | |
65 | 74 | return 0; |
66 | 75 | } |
67 | 76 | |
... | ... | @@ -79,10 +88,6 @@ |
79 | 88 | /* set len to 8 bits */ |
80 | 89 | setbits_be32(&spi->mode, (8 - 1) << SPI_MODE_LEN_SHIFT); |
81 | 90 | |
82 | - /* TODO(mario.six@gdsys.cc): This only ever sets one fixed speed */ | |
83 | - /* Use SYSCLK / 8 (16.67MHz typ.) */ | |
84 | - clrsetbits_be32(&spi->mode, SPI_MODE_PM_MASK, to_prescale_mod(1)); | |
85 | - | |
86 | 91 | setbits_be32(&spi->mode, SPI_MODE_EN); |
87 | 92 | |
88 | 93 | /* Clear all SPI events */ |
... | ... | @@ -204,6 +209,43 @@ |
204 | 209 | |
205 | 210 | static int mpc8xxx_spi_set_speed(struct udevice *dev, uint speed) |
206 | 211 | { |
212 | + struct mpc8xxx_priv *priv = dev_get_priv(dev); | |
213 | + spi8xxx_t *spi = priv->spi; | |
214 | + u32 bits, mask, div16, pm; | |
215 | + u32 mode; | |
216 | + ulong clk; | |
217 | + | |
218 | + clk = priv->clk_rate; | |
219 | + if (clk / 64 > speed) { | |
220 | + div16 = SPI_MODE_DIV16; | |
221 | + clk /= 16; | |
222 | + } else { | |
223 | + div16 = 0; | |
224 | + } | |
225 | + pm = (clk - 1)/(4*speed) + 1; | |
226 | + if (pm > 16) { | |
227 | + dev_err(dev, "requested speed %u too small\n", speed); | |
228 | + return -EINVAL; | |
229 | + } | |
230 | + pm--; | |
231 | + | |
232 | + bits = div16 | (pm << SPI_MODE_PM_SHIFT); | |
233 | + mask = SPI_MODE_DIV16 | SPI_MODE_PM_MASK; | |
234 | + mode = in_be32(&spi->mode); | |
235 | + if ((mode & mask) != bits) { | |
236 | + /* Must clear mode[EN] while changing speed. */ | |
237 | + mode &= ~(mask | SPI_MODE_EN); | |
238 | + out_be32(&spi->mode, mode); | |
239 | + mode |= bits; | |
240 | + out_be32(&spi->mode, mode); | |
241 | + mode |= SPI_MODE_EN; | |
242 | + out_be32(&spi->mode, mode); | |
243 | + } | |
244 | + | |
245 | + debug("requested speed %u, set speed to %lu/(%s4*%u) == %lu\n", | |
246 | + speed, priv->clk_rate, div16 ? "16*" : "", pm + 1, | |
247 | + clk/(4*(pm + 1))); | |
248 | + | |
207 | 249 | return 0; |
208 | 250 | } |
209 | 251 |