Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
981219ee AA |
2 | /* |
3 | * LPC32xx SSP interface (SPI mode) | |
4 | * | |
5 | * (C) Copyright 2014 DENX Software Engineering GmbH | |
6 | * Written-by: Albert ARIBAUD <albert.aribaud@3adev.fr> | |
981219ee AA |
7 | */ |
8 | ||
9 | #include <common.h> | |
10 | #include <linux/compat.h> | |
11 | #include <asm/io.h> | |
12 | #include <malloc.h> | |
13 | #include <spi.h> | |
14 | #include <asm/arch/clk.h> | |
15 | ||
16 | /* SSP chip registers */ | |
17 | struct ssp_regs { | |
18 | u32 cr0; | |
19 | u32 cr1; | |
20 | u32 data; | |
21 | u32 sr; | |
22 | u32 cpsr; | |
23 | u32 imsc; | |
24 | u32 ris; | |
25 | u32 mis; | |
26 | u32 icr; | |
27 | u32 dmacr; | |
28 | }; | |
29 | ||
30 | /* CR1 register defines */ | |
31 | #define SSP_CR1_SSP_ENABLE 0x0002 | |
32 | ||
33 | /* SR register defines */ | |
34 | #define SSP_SR_TNF 0x0002 | |
35 | /* SSP status RX FIFO not empty bit */ | |
36 | #define SSP_SR_RNE 0x0004 | |
37 | ||
38 | /* lpc32xx spi slave */ | |
39 | struct lpc32xx_spi_slave { | |
40 | struct spi_slave slave; | |
41 | struct ssp_regs *regs; | |
42 | }; | |
43 | ||
44 | static inline struct lpc32xx_spi_slave *to_lpc32xx_spi_slave( | |
45 | struct spi_slave *slave) | |
46 | { | |
47 | return container_of(slave, struct lpc32xx_spi_slave, slave); | |
48 | } | |
49 | ||
981219ee AA |
50 | /* the following is called in sequence by do_spi_xfer() */ |
51 | ||
52 | struct spi_slave *spi_setup_slave(uint bus, uint cs, uint max_hz, uint mode) | |
53 | { | |
54 | struct lpc32xx_spi_slave *lslave; | |
55 | ||
56 | /* we only set up SSP0 for now, so ignore bus */ | |
57 | ||
58 | if (mode & SPI_3WIRE) { | |
9b643e31 | 59 | pr_err("3-wire mode not supported"); |
981219ee AA |
60 | return NULL; |
61 | } | |
62 | ||
63 | if (mode & SPI_SLAVE) { | |
9b643e31 | 64 | pr_err("slave mode not supported\n"); |
981219ee AA |
65 | return NULL; |
66 | } | |
67 | ||
68 | if (mode & SPI_PREAMBLE) { | |
9b643e31 | 69 | pr_err("preamble byte skipping not supported\n"); |
981219ee AA |
70 | return NULL; |
71 | } | |
72 | ||
73 | lslave = spi_alloc_slave(struct lpc32xx_spi_slave, bus, cs); | |
74 | if (!lslave) { | |
75 | printf("SPI_error: Fail to allocate lpc32xx_spi_slave\n"); | |
76 | return NULL; | |
77 | } | |
78 | ||
79 | lslave->regs = (struct ssp_regs *)SSP0_BASE; | |
80 | ||
81 | /* | |
82 | * 8 bit frame, SPI fmt, 500kbps -> clock divider is 26. | |
83 | * Set SCR to 0 and CPSDVSR to 26. | |
84 | */ | |
85 | ||
86 | writel(0x7, &lslave->regs->cr0); /* 8-bit chunks, SPI, 1 clk/bit */ | |
87 | writel(26, &lslave->regs->cpsr); /* SSP clock = HCLK/26 = 500kbps */ | |
88 | writel(0, &lslave->regs->imsc); /* do not raise any interrupts */ | |
89 | writel(0, &lslave->regs->icr); /* clear any pending interrupt */ | |
90 | writel(0, &lslave->regs->dmacr); /* do not do DMAs */ | |
91 | writel(SSP_CR1_SSP_ENABLE, &lslave->regs->cr1); /* enable SSP0 */ | |
92 | return &lslave->slave; | |
93 | } | |
94 | ||
95 | void spi_free_slave(struct spi_slave *slave) | |
96 | { | |
97 | struct lpc32xx_spi_slave *lslave = to_lpc32xx_spi_slave(slave); | |
98 | ||
99 | debug("(lpc32xx) spi_free_slave: 0x%08x\n", (u32)lslave); | |
100 | free(lslave); | |
101 | } | |
102 | ||
103 | int spi_claim_bus(struct spi_slave *slave) | |
104 | { | |
105 | /* only one bus and slave so far, always available */ | |
106 | return 0; | |
107 | } | |
108 | ||
109 | int spi_xfer(struct spi_slave *slave, unsigned int bitlen, | |
110 | const void *dout, void *din, unsigned long flags) | |
111 | { | |
112 | struct lpc32xx_spi_slave *lslave = to_lpc32xx_spi_slave(slave); | |
113 | int bytelen = bitlen >> 3; | |
114 | int idx_out = 0; | |
115 | int idx_in = 0; | |
116 | int start_time; | |
117 | ||
118 | start_time = get_timer(0); | |
119 | while ((idx_out < bytelen) || (idx_in < bytelen)) { | |
120 | int status = readl(&lslave->regs->sr); | |
121 | if ((idx_out < bytelen) && (status & SSP_SR_TNF)) | |
122 | writel(((u8 *)dout)[idx_out++], &lslave->regs->data); | |
26658061 | 123 | if ((idx_in < bytelen) && (status & SSP_SR_RNE)) |
981219ee AA |
124 | ((u8 *)din)[idx_in++] = readl(&lslave->regs->data); |
125 | if (get_timer(start_time) >= CONFIG_LPC32XX_SSP_TIMEOUT) | |
126 | return -1; | |
127 | } | |
128 | return 0; | |
129 | } | |
130 | ||
131 | void spi_release_bus(struct spi_slave *slave) | |
132 | { | |
133 | /* do nothing */ | |
134 | } |