m3dev

cortex m3 debug tools -- superceded by mdebug
git clone http://frotz.net/git/m3dev.git
Log | Files | Refs | README | LICENSE

ssp.c (4097B)


      1 #include <fw/io.h>
      2 #include <fw/lib.h>
      3 #include <fw/types.h>
      4 
      5 #include <arch/cpu.h>
      6 #include <arch/hardware.h>
      7 #include <arch/interrupts.h>
      8 #include <arch/ssp.h>
      9 
     10 void printu(const char *fmt, ...);
     11 
     12 struct spi_cfg {
     13 	unsigned addr;
     14 	unsigned rst;
     15 	unsigned clk;
     16 	unsigned div;
     17 	unsigned irq;
     18 };
     19 
     20 struct spi_dev {
     21 	const struct spi_cfg *cfg;
     22 
     23 	u8	bits;
     24 
     25 	void	*in_buf;
     26 	u16	in_len;
     27 	u16	in_pos;
     28 
     29 	void	*out_buf;
     30 	u16	out_len;
     31 	u16	out_pos;
     32 
     33 	void (*cb)(void *data);
     34 	void	*cb_data;
     35 };
     36 
     37 const struct spi_cfg spi_cfgs[] = {
     38 	[0] = {
     39 		.addr = 0x40040000,
     40 		.rst = SSP0_RST_N,
     41 		.clk = SYS_CLK_SSP0,
     42 		.div = SYS_DIV_SSP0,
     43 		.irq = v_ssp0,
     44 	},
     45 	[1] = {
     46 		.addr = 0x40058000,
     47 		.rst = SSP1_RST_N,
     48 		.clk = SYS_CLK_SSP1,
     49 		.div = SYS_DIV_SSP1,
     50 		.irq = v_ssp1,
     51 	},
     52 };
     53 
     54 struct spi_dev spi_devs[] = {
     55 	[0] = {.cfg = &spi_cfgs[0]},
     56 	[1] = {.cfg = &spi_cfgs[1]},
     57 };
     58 
     59 static inline unsigned spi_readl(struct spi_dev *spi, unsigned reg)
     60 {
     61 	return readl(spi->cfg->addr + reg);
     62 }
     63 
     64 static inline void spi_writel(struct spi_dev *spi, unsigned val, unsigned reg)
     65 {
     66 	writel(val, spi->cfg->addr + reg);
     67 }
     68 
     69 static inline void spi_clr_set_reg(struct spi_dev *spi, unsigned reg,
     70 				   unsigned clr, unsigned set)
     71 {
     72 	clr_set_reg(spi->cfg->addr + reg, clr, set);
     73 }
     74 
     75 void handle_spi_xmit(struct spi_dev *spi)
     76 {
     77 	u16 data;
     78 
     79 	/*
     80 	 * Drain the rx fifo. Make sure that we read as many words as we wrote.
     81 	 * If the in_buf len is less that out_len, throw away the word.
     82 	 */
     83 	while(spi->in_pos < spi->out_len &&
     84 	      (spi_readl(spi, SSP_SR) & SSP_SR_RNE)) {
     85 		data = spi_readl(spi, SSP_DR);
     86 
     87 		if (spi->in_pos < spi->in_len) {
     88 			if (spi->bits == 8)
     89 				((u8 *)spi->in_buf)[spi->in_pos] = data;
     90 			else
     91 				((u16 *)spi->in_buf)[spi->in_pos] = data;
     92 		}
     93 		spi->in_pos++;
     94 	}
     95 
     96 	if (spi->in_pos < spi->out_len)
     97 		spi_clr_set_reg(spi, SSP_IMSC, 0, SSP_INT_RT | SSP_INT_RX);
     98 	else
     99 		spi_clr_set_reg(spi, SSP_IMSC, SSP_INT_RT | SSP_INT_RX, 0);
    100 
    101 	/* fill the TX fifo */
    102 	while(spi->out_pos < spi->out_len &&
    103 	      (spi_readl(spi, SSP_SR) & SSP_SR_TNF)) {
    104 		if (spi->bits == 8)
    105 			data = ((u8 *)spi->out_buf)[spi->out_pos];
    106 		else
    107 			data = ((u16 *)spi->out_buf)[spi->out_pos];
    108 		spi_writel(spi, data, SSP_DR);
    109 		spi->out_pos++;
    110 	}
    111 
    112 	if (spi->in_pos < spi->out_len)
    113 		spi_clr_set_reg(spi, SSP_IMSC, 0, SSP_INT_TX);
    114 	else
    115 		spi_clr_set_reg(spi, SSP_IMSC, SSP_INT_TX, 0);
    116 
    117 	if (spi->in_pos < spi->out_len && spi->cb)
    118 		spi->cb(spi->cb_data);
    119 }
    120 
    121 void handle_spi_irq(struct spi_dev *spi)
    122 {
    123 	unsigned status = spi_readl(spi, SSP_RIS);
    124 
    125 	handle_spi_xmit(spi);
    126 
    127 	spi_writel(spi, status & 0x3, SSP_RIS);
    128 }
    129 
    130 void handle_irq_ssp0(void)
    131 {
    132 	handle_spi_irq(&spi_devs[0]);
    133 }
    134 
    135 void handle_irq_ssp1(void)
    136 {
    137 	handle_spi_irq(&spi_devs[1]);
    138 }
    139 
    140 struct spi_dev *ssp_init(unsigned n, int bits, bool cpol, bool cpha,
    141 				 int prescale, int clkdiv, int rate)
    142 {
    143 	struct spi_dev *spi;
    144 	const struct spi_cfg *cfg;
    145 	if (n > ARRAY_SIZE(spi_devs))
    146 		return NULL;
    147 
    148 	spi = &spi_devs[n];
    149 	cfg = spi->cfg;
    150 	spi->bits = bits;
    151 
    152 	irq_enable(cfg->irq);
    153 
    154 	/* assert reset, disable clock */
    155 	writel(readl(PRESETCTRL) & ~cfg->rst, PRESETCTRL);
    156 	writel(0, cfg->div);
    157 
    158 	/* enable SSP0 clock */
    159 	writel(readl(SYS_CLK_CTRL) | cfg->clk, SYS_CLK_CTRL);
    160 
    161 	/* SSP0 PCLK = SYSCLK / 3 (16MHz) */
    162 	writel(clkdiv, cfg->div);
    163 
    164 	/* deassert reset */
    165 	writel(readl(PRESETCTRL) | cfg->rst, PRESETCTRL);
    166 
    167 	spi_writel(spi, prescale, SSP_CPSR); /* prescale = PCLK/2 */
    168 	spi_writel(spi, SSP_CR0_BITS(bits) | SSP_CR0_FRAME_SPI |
    169 		   (cpol ? SSP_CR0_CPOL : 0) |
    170 		   (cpha ? SSP_CR0_CPHA : 0) |
    171 		   SSP_CR0_CLOCK_RATE(rate),
    172 		   SSP_CR0);
    173         spi_writel(spi, SSP_CR1_ENABLE | SSP_CR1_MASTER, SSP_CR1);
    174 
    175 	return spi;
    176 }
    177 
    178 void spi_xmit(struct spi_dev *spi, void *out_buf, int out_len,
    179 	      void *in_buf, int in_len,
    180 	      void (*cb)(void *data), void *cb_data)
    181 {
    182 	/* wait for spi to idle */
    183 	while (spi_readl(spi, SSP_SR) & SSP_SR_BSY) {
    184 	}
    185 
    186 	spi->in_buf = in_buf;
    187 	spi->in_len = in_len;
    188 	spi->in_pos = 0;
    189 
    190 	spi->out_buf = out_buf;
    191 	spi->out_len = out_len;
    192 	spi->out_pos = 0;
    193 
    194 	spi->cb = cb;
    195 	spi->cb_data = cb_data;
    196 
    197 	disable_interrupts();
    198 	handle_spi_xmit(spi);
    199 	enable_interrupts();
    200 }