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