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 }