import cbaos v0.1
[cbaos.git] / drivers / spi / lpc21xx_spi.c
blob9e868b59de3e7b92b0acefe752e3303aef834c5c
1 /* Author: Domen Puncer <domen@cba.si>. License: WTFPL, see file LICENSE */
2 #include <stdio.h>
3 #include <string.h>
4 #include <errno.h>
6 #include <interrupt.h>
7 #include <types.h>
8 #include <gpio.h>
9 #include <compiler.h>
10 #include <mach/lpc21xx_gpio.h>
11 #include <mach/lpc21xx_regs.h>
12 #include <drivers/spi.h>
13 #include <drivers/lpc_spi.h>
17 static int lpc_spi_change_device(struct spi_device *device)
19 struct lpc_spi *spi = device->master->spi;
20 struct lpc_spi_data *data = device->master->spi_data;
21 int tmp;
22 int spi_cr = 0;
24 if (device->mode & SPI_CPHA)
25 spi_cr |= 1<<3;
26 if (device->mode & SPI_CPOL)
27 spi_cr |= 1<<4;
28 spi_cr |= 1<<5; /* MSTR master mode */
29 if (device->mode & SPI_LSB)
30 spi_cr |= 1<<6; /* LSBF LSB first */
32 spi_cr |= 1<<7; /* SPIE interrupt enable */
33 spi->SPINT = 1; /* clear old interrupt */
34 irq_enable(IRQ_SPI0);
36 spi->SPCR = spi_cr;
37 tmp = (data->pclk + device->clock-1) / device->clock;
38 tmp &= ~1;
39 if (tmp < 8)
40 tmp = 8;
41 if (tmp > 255)
42 tmp = 254;
43 /* this limits spi clock to pclk/8 */
44 spi->SPCCR = tmp;
46 gpio_init(device->cs_pin, GPIO_OUTPUT, 1);
48 return 0;
51 static void lpc_spi_tx(struct lpc_spi *spi, u8 data)
53 spi->SPDR = data;
56 static struct spi0_irq_data {
57 struct spi_device *device;
58 struct spi_transfer *transfer;
59 int pos;
60 } spi0_irq_data;
62 void __interrupt spi0_handler()
64 struct lpc_spi *spi = spi0_irq_data.device->master->spi;
65 struct spi_transfer *transfer = spi0_irq_data.transfer;
66 int pos = spi0_irq_data.pos;
68 spi->SPINT = 1; /* clear spi interrupt */
69 VICVectAddr = 0; /* clear pending interrupt */
71 if ((spi->SPSR & 1<<7) == 0) {
72 printf("%s: should error out with spi_transfer_finished\n", __func__);
73 transfer->error = -EINVAL;
74 spi_transfer_finished(spi0_irq_data.device, transfer);
75 return;
77 transfer->rx_buf[pos++] = spi->SPDR;
79 if (pos >= transfer->len) {
80 gpio_set(spi0_irq_data.device->cs_pin, 1);
81 spi_transfer_finished(spi0_irq_data.device, transfer);
82 } else {
83 lpc_spi_tx(spi, transfer->tx_buf[pos]);
86 spi0_irq_data.pos = pos;
89 static int lpc_spi_transfer(struct spi_device *device, struct spi_transfer *transfer)
91 struct lpc_spi *spi = device->master->spi;
93 spi0_irq_data.pos = 0;
94 spi0_irq_data.device = device;
95 spi0_irq_data.transfer = transfer;
97 gpio_set(device->cs_pin, 0);
98 lpc_spi_tx(spi, transfer->tx_buf[0]);
100 /* after this, the irq routine picks up */
102 return 0;
106 int lpc_spi_register(struct spi_master *master)
108 /* some init goes here... which isn't needed in this case */
110 master->change_device = lpc_spi_change_device;
111 master->transfer = lpc_spi_transfer;
112 return 0;