2 * Copyright © 2013 Keith Packard <keithp@keithp.com>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
20 static uint8_t ao_spi_mutex[LPC_NUM_SPI];
22 struct ao_lpc_ssp_state {
31 static struct ao_lpc_ssp_state ao_lpc_ssp_state[LPC_NUM_SPI];
33 static struct lpc_ssp * const ao_lpc_ssp[LPC_NUM_SPI] = { &lpc_ssp0, &lpc_ssp1 };
36 ao_lpc_ssp_recv(struct lpc_ssp *lpc_ssp, struct ao_lpc_ssp_state *state)
38 while ((lpc_ssp->sr & (1 << LPC_SSP_SR_RNE)) &&
41 /* RX ready, read a byte */
42 *state->rx = lpc_ssp->dr;
43 state->rx += state->rx_inc;
49 ao_lpc_ssp_isr(struct lpc_ssp *lpc_ssp, struct ao_lpc_ssp_state *state)
51 ao_lpc_ssp_recv(lpc_ssp, state);
52 while ((lpc_ssp->sr & (1 << LPC_SSP_SR_TNF)) &&
55 /* TX ready, write a byte */
56 lpc_ssp->dr = *state->tx;
57 state->tx += state->tx_inc;
59 ao_lpc_ssp_recv(lpc_ssp, state);
61 if (!state->rx_count) {
62 lpc_ssp->imsc &= ~(1 << LPC_SSP_IMSC_TXIM);
70 ao_lpc_ssp_isr(&lpc_ssp0, &ao_lpc_ssp_state[0]);
76 ao_lpc_ssp_isr(&lpc_ssp1, &ao_lpc_ssp_state[1]);
80 ao_spi_run(struct lpc_ssp *lpc_ssp, struct ao_lpc_ssp_state *state)
82 ao_arch_block_interrupts();
83 lpc_ssp->imsc = (1 << LPC_SSP_IMSC_TXIM);
84 while (state->rx_count)
86 ao_arch_release_interrupts();
89 static uint8_t ao_spi_tx_dummy = 0xff;
90 static uint8_t ao_spi_rx_dummy;
93 ao_spi_send(const void *block, uint16_t len, uint8_t id)
95 struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id];
96 struct ao_lpc_ssp_state *state = &ao_lpc_ssp_state[id];
98 state->tx_count = state->rx_count = len;
101 state->rx = &ao_spi_rx_dummy;
103 ao_spi_run(lpc_ssp, state);
107 ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t id)
109 struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id];
110 struct ao_lpc_ssp_state *state = &ao_lpc_ssp_state[id];
112 state->tx_count = state->rx_count = len;
115 state->rx = &ao_spi_rx_dummy;
117 ao_spi_run(lpc_ssp, state);
121 ao_spi_recv(void *block, uint16_t len, uint8_t id)
123 struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id];
124 struct ao_lpc_ssp_state *state = &ao_lpc_ssp_state[id];
126 state->tx_count = state->rx_count = len;
127 state->tx = &ao_spi_tx_dummy;
131 ao_spi_run(lpc_ssp, state);
135 ao_spi_duplex(const void *out, void *in, uint16_t len, uint8_t id)
137 struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id];
138 struct ao_lpc_ssp_state *state = &ao_lpc_ssp_state[id];
140 state->tx_count = state->rx_count = len;
145 ao_spi_run(lpc_ssp, state);
149 ao_spi_get(uint8_t id, uint32_t speed)
151 struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id];
153 ao_mutex_get(&ao_spi_mutex[id]);
155 /* Set the clock prescale */
156 lpc_ssp->cpsr = speed;
160 ao_spi_put(uint8_t id)
162 ao_mutex_put(&ao_spi_mutex[id]);
166 ao_spi_channel_init(uint8_t id)
168 struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id];
171 /* Clear interrupt registers */
176 lpc_ssp->cr0 = ((LPC_SSP_CR0_DSS_8 << LPC_SSP_CR0_DSS) |
177 (LPC_SSP_CR0_FRF_SPI << LPC_SSP_CR0_FRF) |
178 (0 << LPC_SSP_CR0_CPOL) |
179 (0 << LPC_SSP_CR0_CPHA) |
180 (0 << LPC_SSP_CR0_SCR));
182 /* Enable the device */
183 lpc_ssp->cr1 = ((0 << LPC_SSP_CR1_LBM) |
184 (1 << LPC_SSP_CR1_SSE) |
185 (LPC_SSP_CR1_MS_MASTER << LPC_SSP_CR1_MS) |
186 (0 << LPC_SSP_CR1_SOD));
188 /* Drain the receive fifo */
189 for (d = 0; d < LPC_SSP_FIFOSIZE; d++)
199 lpc_ioconf.pio0_6 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO0_6_SCK0);
203 lpc_ioconf.pio0_10 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO0_10_SCK0);
207 lpc_ioconf.pio1_29 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO1_29_SCK0);
211 #error "No pin specified for SCK0"
213 lpc_ioconf.pio0_8 = ao_lpc_alternate(LPC_IOCONF_FUNC_MISO0);
214 lpc_ioconf.pio0_9 = ao_lpc_alternate(LPC_IOCONF_FUNC_MOSI0);
216 /* Enable the device */
217 lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_SSP0);
219 /* Turn on the clock */
220 lpc_scb.ssp0clkdiv = 1;
222 /* Reset the device */
223 lpc_scb.presetctrl &= ~(1 << LPC_SCB_PRESETCTRL_SSP0_RST_N);
224 lpc_scb.presetctrl |= (1 << LPC_SCB_PRESETCTRL_SSP0_RST_N);
225 ao_spi_channel_init(0);
228 lpc_nvic_set_enable(LPC_ISR_SSP0_POS);
229 lpc_nvic_set_priority(LPC_ISR_SSP0_POS, 0);
235 lpc_ioconf.pio1_15 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO1_15_SCK1);
239 lpc_ioconf.pio1_20 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO1_20_SCK1);
243 #error "No pin specified for SCK1"
247 lpc_ioconf.pio0_22 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO0_22_MISO1);
251 lpc_ioconf.pio1_21 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO1_21_MISO1);
255 #error "No pin specified for MISO1"
259 lpc_ioconf.pio0_21 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO0_21_MOSI1);
263 lpc_ioconf.pio1_22 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO1_22_MOSI1);
267 #error "No pin specified for MOSI1"
270 /* Enable the device */
271 lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_SSP1);
273 /* Turn on the clock */
274 lpc_scb.ssp1clkdiv = 1;
276 /* Reset the device */
277 lpc_scb.presetctrl &= ~(1 << LPC_SCB_PRESETCTRL_SSP1_RST_N);
278 lpc_scb.presetctrl |= (1 << LPC_SCB_PRESETCTRL_SSP1_RST_N);
279 ao_spi_channel_init(1);
282 lpc_nvic_set_enable(LPC_ISR_SSP1_POS);
283 lpc_nvic_set_priority(LPC_ISR_SSP1_POS, 0);
285 #endif /* HAS_SPI_1 */