Merge tag 'u-boot-rockchip-20191231' of https://gitlab.denx.de/u-boot/custodians...
[oweals/u-boot.git] / drivers / spi / mscc_bb_spi.c
1 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
2 /*
3  * Microsemi SoCs spi driver
4  *
5  * Copyright (c) 2018 Microsemi Corporation
6  */
7
8 #include <common.h>
9 #include <dm.h>
10 #include <errno.h>
11 #include <malloc.h>
12 #include <spi.h>
13 #include <dm.h>
14 #include <asm/gpio.h>
15 #include <asm/io.h>
16 #include <linux/delay.h>
17
18 struct mscc_bb_priv {
19         void __iomem *regs;
20         u32 deactivate_delay_us;
21         bool cs_active;   /* State flag as to whether CS is asserted */
22         int cs_num;
23         u32 svalue;                     /* Value to start transfer with */
24         u32 clk1;                       /* Clock value start */
25         u32 clk2;                       /* Clock value 2nd phase */
26 };
27
28 /* Delay 24 instructions for this particular application */
29 #define hold_time_delay() mscc_vcoreiii_nop_delay(3)
30
31 static int mscc_bb_spi_cs_activate(struct mscc_bb_priv *priv, int mode, int cs)
32 {
33         if (!priv->cs_active) {
34                 int cpha = mode & SPI_CPHA;
35                 u32 cs_value;
36
37                 priv->cs_num = cs;
38
39                 if (cpha) {
40                         /* Initial clock starts SCK=1 */
41                         priv->clk1 = ICPU_SW_MODE_SW_SPI_SCK;
42                         priv->clk2 = 0;
43                 } else {
44                         /* Initial clock starts SCK=0 */
45                         priv->clk1 = 0;
46                         priv->clk2 = ICPU_SW_MODE_SW_SPI_SCK;
47                 }
48
49                 /* Enable bitbang, SCK_OE, SDO_OE */
50                 priv->svalue = (ICPU_SW_MODE_SW_PIN_CTRL_MODE | /* Bitbang */
51                                 ICPU_SW_MODE_SW_SPI_SCK_OE    | /* SCK_OE */
52                                 ICPU_SW_MODE_SW_SPI_SDO_OE);   /* SDO OE */
53
54                 /* Add CS */
55                 if (cs >= 0) {
56                         cs_value =
57                                 ICPU_SW_MODE_SW_SPI_CS_OE(BIT(cs)) |
58                                 ICPU_SW_MODE_SW_SPI_CS(BIT(cs));
59                 } else {
60                         cs_value = 0;
61                 }
62
63                 priv->svalue |= cs_value;
64
65                 /* Enable the CS in HW, Initial clock value */
66                 writel(priv->svalue | priv->clk2, priv->regs);
67
68                 priv->cs_active = true;
69                 debug("Activated CS%d\n", priv->cs_num);
70         }
71
72         return 0;
73 }
74
75 static int mscc_bb_spi_cs_deactivate(struct mscc_bb_priv *priv, int deact_delay)
76 {
77         if (priv->cs_active) {
78                 /* Keep driving the CLK to its current value while
79                  * actively deselecting CS.
80                  */
81                 u32 value = readl(priv->regs);
82
83                 value &= ~ICPU_SW_MODE_SW_SPI_CS_M;
84                 writel(value, priv->regs);
85                 hold_time_delay();
86
87                 /* Stop driving the clock, but keep CS with nCS == 1 */
88                 value &= ~ICPU_SW_MODE_SW_SPI_SCK_OE;
89                 writel(value, priv->regs);
90
91                 /* Deselect hold time delay */
92                 if (deact_delay)
93                         udelay(deact_delay);
94
95                 /* Drop everything */
96                 writel(0, priv->regs);
97
98                 priv->cs_active = false;
99                 debug("Deactivated CS%d\n", priv->cs_num);
100         }
101
102         return 0;
103 }
104
105 int mscc_bb_spi_claim_bus(struct udevice *dev)
106 {
107         return 0;
108 }
109
110 int mscc_bb_spi_release_bus(struct udevice *dev)
111 {
112         return 0;
113 }
114
115 int mscc_bb_spi_xfer(struct udevice *dev, unsigned int bitlen,
116                      const void *dout, void *din, unsigned long flags)
117 {
118         struct udevice *bus = dev_get_parent(dev);
119         struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev);
120         struct mscc_bb_priv *priv = dev_get_priv(bus);
121         u32             i, count;
122         const u8        *txd = dout;
123         u8              *rxd = din;
124
125         debug("spi_xfer: slave %s:%s cs%d mode %d, dout %p din %p bitlen %u\n",
126               dev->parent->name, dev->name, plat->cs,  plat->mode, dout,
127               din, bitlen);
128
129         if (flags & SPI_XFER_BEGIN)
130                 mscc_bb_spi_cs_activate(priv, plat->mode, plat->cs);
131
132         count = bitlen / 8;
133         for (i = 0; i < count; i++) {
134                 u32 rx = 0, mask = 0x80, value;
135
136                 while (mask) {
137                         /* Initial condition: CLK is low. */
138                         value = priv->svalue;
139                         if (txd && txd[i] & mask)
140                                 value |= ICPU_SW_MODE_SW_SPI_SDO;
141
142                         /* Drive data while taking CLK low. The device
143                          * we're accessing will sample on the
144                          * following rising edge and will output data
145                          * on this edge for us to be sampled at the
146                          * end of this loop.
147                          */
148                         writel(value | priv->clk1, priv->regs);
149
150                         /* Wait for t_setup. All devices do have a
151                          * setup-time, so we always insert some delay
152                          * here. Some devices have a very long
153                          * setup-time, which can be adjusted by the
154                          * user through vcoreiii_device->delay.
155                          */
156                         hold_time_delay();
157
158                         /* Drive the clock high. */
159                         writel(value | priv->clk2, priv->regs);
160
161                         /* Wait for t_hold. See comment about t_setup
162                          * above.
163                          */
164                         hold_time_delay();
165
166                         /* We sample as close to the next falling edge
167                          * as possible.
168                          */
169                         value = readl(priv->regs);
170                         if (value & ICPU_SW_MODE_SW_SPI_SDI)
171                                 rx |= mask;
172                         mask >>= 1;
173                 }
174                 if (rxd) {
175                         debug("Read 0x%02x\n", rx);
176                         rxd[i] = (u8)rx;
177                 }
178                 debug("spi_xfer: byte %d/%d\n", i + 1, count);
179         }
180
181         debug("spi_xfer: done\n");
182
183         if (flags & SPI_XFER_END)
184                 mscc_bb_spi_cs_deactivate(priv, priv->deactivate_delay_us);
185
186         return 0;
187 }
188
189 int mscc_bb_spi_set_speed(struct udevice *dev, unsigned int speed)
190 {
191         /* Accept any speed */
192         return 0;
193 }
194
195 int mscc_bb_spi_set_mode(struct udevice *dev, unsigned int mode)
196 {
197         return 0;
198 }
199
200 static const struct dm_spi_ops mscc_bb_ops = {
201         .claim_bus      = mscc_bb_spi_claim_bus,
202         .release_bus    = mscc_bb_spi_release_bus,
203         .xfer           = mscc_bb_spi_xfer,
204         .set_speed      = mscc_bb_spi_set_speed,
205         .set_mode       = mscc_bb_spi_set_mode,
206 };
207
208 static const struct udevice_id mscc_bb_ids[] = {
209         { .compatible = "mscc,luton-bb-spi" },
210         { }
211 };
212
213 static int mscc_bb_spi_probe(struct udevice *bus)
214 {
215         struct mscc_bb_priv *priv = dev_get_priv(bus);
216
217         debug("%s: loaded, priv %p\n", __func__, priv);
218
219         priv->regs = (void __iomem *)dev_read_addr(bus);
220
221         priv->deactivate_delay_us =
222                 dev_read_u32_default(bus, "spi-deactivate-delay", 0);
223
224         priv->cs_active = false;
225
226         return 0;
227 }
228
229 U_BOOT_DRIVER(mscc_bb) = {
230         .name   = "mscc_bb",
231         .id     = UCLASS_SPI,
232         .of_match = mscc_bb_ids,
233         .ops    = &mscc_bb_ops,
234         .priv_auto_alloc_size = sizeof(struct mscc_bb_priv),
235         .probe  = mscc_bb_spi_probe,
236 };