]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/glsdk-u-boot.git/blob - drivers/spi/ti_qspi.c
drivers: mtd: qspi: Add quad read support
[glsdk/glsdk-u-boot.git] / drivers / spi / ti_qspi.c
1 /*
2  * TI QSPI driver
3  *
4  * Copyright (C) 2013, Texas Instruments, Incorporated
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of
9  * the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR /PURPOSE.  See the
14  * GNU General Public License for more details.
15  */
17 #include <common.h>
18 #include <asm/io.h>
19 #include <asm/arch/omap.h>
20 #include <malloc.h>
21 #include <spi.h>
23 struct qspi_slave {
24         struct spi_slave slave;
25         unsigned int mode;
26         u32 cmd;
27         u32 dc;
28 };
30 #define to_qspi_slave(s) container_of(s, struct qspi_slave, slave)
32 struct qspi_regs {
33         u32 pid;
34         u32 pad0[3];
35         u32 sysconfig;
36         u32 pad1[3];
37         u32 intr_status_raw_set;
38         u32 intr_status_enabled_clear;
39         u32 intr_enable_set;
40         u32 intr_enable_clear;
41         u32 intc_eoi;
42         u32 pad2[3];
43         u32 spi_clock_cntrl;
44         u32 spi_dc;
45         u32 spi_cmd;
46         u32 spi_status;
47         u32 spi_data;
48         u32 spi_setup0;
49         u32 spi_setup1;
50         u32 spi_setup2;
51         u32 spi_setup3;
52         u32 spi_switch;
53         u32 spi_data1;
54         u32 spi_data2;
55         u32 spi_data3;
56 };
58 static struct qspi_regs *qspi = (struct qspi_regs *)QSPI_BASE;
60 #define QSPI_TIMEOUT                    2000000
62 #define QSPI_FCLK                       192000000
64 /* Clock Control */
65 #define QSPI_CLK_EN                     (1 << 31)
66 #define QSPI_CLK_DIV_MAX                0xffff
68 /* Command */
69 #define QSPI_EN_CS(n)                   (n << 28)
70 #define QSPI_WLEN(n)                    ((n-1) << 19)
71 #define QSPI_3_PIN                      (1 << 18)
72 #define QSPI_RD_SNGL                    (1 << 16)
73 #define QSPI_WR_SNGL                    (2 << 16)
74 #define QSPI_INVAL                      (4 << 16)
75 #define QSPI_RD_QUAD                    (7 << 16)
77 /* Device Control */
78 #define QSPI_DD(m, n)                   (m << (3 + n*8))
79 #define QSPI_CKPHA(n)                   (1 << (2 + n*8))
80 #define QSPI_CSPOL(n)                   (1 << (1 + n*8))
81 #define QSPI_CKPOL(n)                   (1 << (n*8))
83 /* Status */
84 #define QSPI_WC                         (1 << 1)
85 #define QSPI_BUSY                       (1 << 0)
86 #define QSPI_WC_BUSY                    (QSPI_WC | QSPI_BUSY)
87 #define QSPI_XFER_DONE                  QSPI_WC
89 int spi_cs_is_valid(unsigned int bus, unsigned int cs)
90 {
91         return 1;
92 }
94 void spi_cs_activate(struct spi_slave *slave)
95 {
96         /* CS handled in xfer */
97         return;
98 }
100 void spi_cs_deactivate(struct spi_slave *slave)
102         /* CS handled in xfer */
103         return;
106 void spi_init(void)
108         /* nothing to do */
111 void spi_set_speed(struct spi_slave *slave, uint hz)
113         uint clk_div;
115         if (!hz)
116                 clk_div = 0;
117         else
118                 clk_div = (QSPI_FCLK / hz) - 1;
120         debug("%s: hz: %d, clock divider %d\n", __func__, hz, clk_div);
122         /* disable SCLK */
123         writel(readl(&qspi->spi_clock_cntrl) & ~QSPI_CLK_EN, &qspi->spi_clock_cntrl);
125         if (clk_div < 0) {
126                 debug("%s: clock divider < 0, using /1 divider\n", __func__);
127                 clk_div = 0;
128         }
130         if (clk_div > QSPI_CLK_DIV_MAX) {
131                 debug("%s: clock divider >%d , using /%d divider\n",
132                         __func__, QSPI_CLK_DIV_MAX, QSPI_CLK_DIV_MAX + 1);
133                 clk_div = QSPI_CLK_DIV_MAX;
134         }
136         /* enable SCLK */
137         writel(QSPI_CLK_EN | clk_div, &qspi->spi_clock_cntrl);
138         debug("%s: spi_clock_cntrl %08x\n", __func__, readl(&qspi->spi_clock_cntrl));
141 struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
142                                   unsigned int max_hz, unsigned int mode)
144         struct qspi_slave *qslave;
146         qslave = spi_alloc_slave(struct qspi_slave, bus, cs);
147         if (!qslave)
148                 return NULL;
150         spi_set_speed(&qslave->slave, max_hz);
151         qslave->mode = mode;
152         debug("%s: bus:%i cs:%i mode:%i\n", __func__, bus, cs, mode);
154         return &qslave->slave;
157 void spi_free_slave(struct spi_slave *slave)
159         struct qspi_slave *qslave = to_qspi_slave(slave);
160         free(qslave);
163 int spi_claim_bus(struct spi_slave *slave)
165         debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
167         writel(0, &qspi->spi_dc);
168         writel(0, &qspi->spi_cmd);
169         writel(0, &qspi->spi_data);
171         return 0;
174 void spi_release_bus(struct spi_slave *slave)
176         debug("%s: bus:%i cs:%i\n", __func__, slave->bus, slave->cs);
178         writel(0, &qspi->spi_dc);
179         writel(0, &qspi->spi_cmd);
180         writel(0, &qspi->spi_data);
183 int spi_xfer(struct spi_slave *slave, unsigned int bitlen, const void *dout,
184              void *din, unsigned long flags)
186         struct qspi_slave *qslave = to_qspi_slave(slave);
187         uint words = bitlen >> 3; /* fixed 8-bit word length */
188         const uchar *txp = dout;
189         uchar *rxp = din;
190         uint status;
191         int timeout;
193         debug("%s: bus:%i cs:%i bitlen:%i words:%i flags:%lx\n", __func__,
194                 slave->bus, slave->cs, bitlen, words, flags);
195         if (bitlen == 0)
196                 return -1;
198         if (bitlen % 8) {
199                 flags |= SPI_XFER_END;
200                 return -1;
201         }
203         /* setup command reg */
204         qslave->cmd = 0;
205         qslave->cmd |= QSPI_WLEN(8);
206         qslave->cmd |= QSPI_EN_CS(slave->cs);
207         if (flags & SPI_3WIRE)
208                 qslave->cmd |= QSPI_3_PIN;
209         qslave->cmd |= 0xfff;
211         /* setup device control reg */
212         qslave->dc = 0;
213         if (qslave->mode & SPI_CPHA)
214                 qslave->dc |= QSPI_CKPHA(slave->cs);
215         if (qslave->mode & SPI_CPOL)
216                 qslave->dc |= QSPI_CKPOL(slave->cs);
217         if (qslave->mode & SPI_CS_HIGH)
218                 qslave->dc |= QSPI_CSPOL(slave->cs);
220         while (words--) {
221                 if (txp) {
222                         debug("tx cmd %08x dc %08x data %02x\n",
223                               qslave->cmd | QSPI_WR_SNGL, qslave->dc, *txp);
224                         writel(*txp++, &qspi->spi_data);
225                         writel(qslave->dc, &qspi->spi_dc);
226                         writel(qslave->cmd | QSPI_WR_SNGL, &qspi->spi_cmd);
227                         status = readl(&qspi->spi_status);
228                         timeout = QSPI_TIMEOUT;
229                         while ((status & QSPI_WC_BUSY) != QSPI_XFER_DONE) {
230                                 if (--timeout < 0) {
231                                         printf("QSPI tx timed out\n");
232                                         return -1;
233                                 }
234                                 status = readl(&qspi->spi_status);
235                         }
236                         debug("tx done, status %08x\n", status);
237                 }
238                 if (rxp) {
239                         if (flags & SPI_6WIRE) {
240                                 debug("rx cmd %08x dc %08x\n",
241                                       qslave->cmd | QSPI_RD_QUAD, qslave->dc);
242                                 writel(qslave->cmd | QSPI_RD_QUAD,
243                                        &qspi->spi_cmd);
244                         } else {
245                                 debug("rx cmd %08x dc %08x\n",
246                                       qslave->cmd | QSPI_RD_SNGL, qslave->dc);
247                                 writel(qslave->cmd | QSPI_RD_SNGL,
248                                        &qspi->spi_cmd);
249                         }
250                         status = readl(&qspi->spi_status);
251                         timeout = QSPI_TIMEOUT;
252                         while ((status & QSPI_WC_BUSY) != QSPI_XFER_DONE) {
253                                 if (--timeout < 0) {
254                                         printf("QSPI rx timed out\n");
255                                         return -1;
256                                 }
257                                 status = readl(&qspi->spi_status);
258                         }
259                         *rxp++ = readl(&qspi->spi_data);
260                         debug("rx done, status %08x, read %02x\n",
261                                  status, *(rxp-1));
262                 }
263         }
265         /* Terminate frame */
266         if (flags & SPI_XFER_END)
267                 writel(qslave->cmd | QSPI_INVAL, &qspi->spi_cmd);
269         return 0;