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 static struct lpc_ssp * const ao_lpc_ssp[LPC_NUM_SPI] = { &lpc_ssp0, &lpc_ssp1 };
24 static uint8_t spi_dev_null;
26 #define tx_busy(lpc_ssp) (lpc_ssp->sr & ((1 << LPC_SSP_SR_BSY) | (1 << LPC_SSP_SR_TNF))) != (1 << LPC_SSP_SR_TNF)
27 #define rx_busy(lpc_ssp) (lpc_ssp->sr & ((1 << LPC_SSP_SR_BSY) | (1 << LPC_SSP_SR_RNE))) != (1 << LPC_SSP_SR_RNE)
29 #define spi_loop(len, put, get) do { \
31 /* Wait for space in the fifo */ \
32 while (tx_busy(lpc_ssp)) \
38 /* Wait for byte to appear in the fifo */ \
39 while (rx_busy(lpc_ssp)) \
48 ao_spi_send(void *block, uint16_t len, uint8_t id)
51 struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id];
53 spi_loop(len, *b++, (void));
57 ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t id)
59 struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id];
61 spi_loop(len, value, (void));
65 ao_spi_recv(void *block, uint16_t len, uint8_t id)
68 struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id];
70 spi_loop(len, 0xff, *b++ =);
74 ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t id)
78 struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id];
80 spi_loop(len, *o++, *i++ =);
84 ao_spi_get(uint8_t id, uint32_t speed)
86 struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id];
88 ao_mutex_get(&ao_spi_mutex[id]);
90 /* Set the clock prescale */
91 lpc_ssp->cpsr = speed;
95 ao_spi_put(uint8_t id)
97 ao_mutex_put(&ao_spi_mutex[id]);
101 ao_spi_channel_init(uint8_t id)
103 struct lpc_ssp *lpc_ssp = ao_lpc_ssp[id];
106 lpc_ssp->cr0 = ((LPC_SSP_CR0_DSS_8 << LPC_SSP_CR0_DSS) |
107 (LPC_SSP_CR0_FRF_SPI << LPC_SSP_CR0_FRF) |
108 (0 << LPC_SSP_CR0_CPOL) |
109 (0 << LPC_SSP_CR0_CPHA) |
110 (0 << LPC_SSP_CR0_SCR));
112 /* Enable the device */
113 lpc_ssp->cr1 = ((0 << LPC_SSP_CR1_LBM) |
114 (1 << LPC_SSP_CR1_SSE) |
115 (LPC_SSP_CR1_MS_MASTER << LPC_SSP_CR1_MS) |
116 (0 << LPC_SSP_CR1_SOD));
118 /* Drain the receive fifo */
119 for (d = 0; d < LPC_SSP_FIFOSIZE; d++)
129 lpc_ioconf.pio0_6 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO0_6_SCK0);
133 lpc_ioconf.pio0_10 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO0_10_SCK0);
137 lpc_ioconf.pio1_29 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO1_29_SCK0);
141 #error "No pin specified for SCK0"
143 lpc_ioconf.pio0_8 = ao_lpc_alternate(LPC_IOCONF_FUNC_MISO0);
144 lpc_ioconf.pio0_9 = ao_lpc_alternate(LPC_IOCONF_FUNC_MOSI0);
146 /* Enable the device */
147 lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_SSP0);
149 /* Turn on the clock */
150 lpc_scb.ssp0clkdiv = 1;
152 /* Reset the device */
153 lpc_scb.presetctrl &= ~(1 << LPC_SCB_PRESETCTRL_SSP0_RST_N);
154 lpc_scb.presetctrl |= (1 << LPC_SCB_PRESETCTRL_SSP0_RST_N);
155 ao_spi_channel_init(0);
161 lpc_ioconf.pio1_15 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO1_15_SCK1);
165 lpc_ioconf.pio1_20 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO1_20_SCK1);
169 #error "No pin specified for SCK1"
173 lpc_ioconf.pio0_22 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO0_22_MISO1);
177 lpc_ioconf.pio1_21 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO1_21_MISO1);
181 #error "No pin specified for MISO1"
185 lpc_ioconf.pio0_21 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO0_21_MOSI1);
189 lpc_ioconf.pio1_22 = ao_lpc_alternate(LPC_IOCONF_FUNC_PIO1_22_MOSI1);
193 #error "No pin specified for MOSI1"
196 /* Enable the device */
197 lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_SSP1);
199 /* Turn on the clock */
200 lpc_scb.ssp1clkdiv = 1;
202 /* Reset the device */
203 lpc_scb.presetctrl &= ~(1 << LPC_SCB_PRESETCTRL_SSP1_RST_N);
204 lpc_scb.presetctrl |= (1 << LPC_SCB_PRESETCTRL_SSP1_RST_N);
205 ao_spi_channel_init(1);
206 #endif /* HAS_SPI_1 */