robocar-led/vendor/periph.io/x/host/v3/allwinner/spi.go

208 lines
7.1 KiB
Go
Raw Normal View History

2019-12-14 10:56:22 +00:00
// Copyright 2016 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
package allwinner
import (
"errors"
"fmt"
"log"
"time"
)
const (
// 31:20 reserved
// Set this bit to 1 to make the internal read sample point with a delay of
// half cycle of SPI_CLK. It is used in high speed read operation to reduce
// the error caused by the time delay of SPI_CLK propagating between master
// and slave.
// 1 delay internal read sample point
// 0 normal operation, do not delay internal read sample point
spiR8HalfDelay spiR8Ctl = 1 << 19 // Master Sample Data Control
spiR8TransmitPause spiR8Ctl = 1 << 18 // Transmit Pause Enable
spiR8CSLevel spiR8Ctl = 1 << 17 // SS_LEVEL; Chip Select level
spiR8CSManual spiR8Ctl = 1 << 16 // SS_CTRL; Do not switch CS automatically
spiR8DiscardHash spiR8Ctl = 1 << 15 // DHB
spiR8DummyBurst spiR8Ctl = 1 << 14 // DDB
spiR8CS0 spiR8Ctl = 0 << 12 // SS; Which CS line to use. For SPI0 only
spiR8CS1 spiR8Ctl = 1 << 12 //
spiR8CS2 spiR8Ctl = 2 << 12 //
spiR8CS3 spiR8Ctl = 3 << 12 //
spiR8RapidsReadMode spiR8Ctl = 1 << 11 // RPSM
spiR8ExchangeBurst spiR8Ctl = 1 << 10 // XCH
spiR8RXFIFOReset spiR8Ctl = 1 << 9 // RXFIFO Reset; Write to reset the FIFO as empty
spiR8TXFIFOReset spiR8Ctl = 1 << 8 // TXFIFO Reset; Write to reset the FIFO as empty
spiR8CSBetweenBursts spiR8Ctl = 1 << 7 // SSCTL
spiR8LSB spiR8Ctl = 1 << 6 // LMTF; MSB by default, LSB when set
spiR8DDMA spiR8Ctl = 1 << 5 // DMAM; Use dedicated DMA if set, normal DMA otherwise
spiR8CSActiveLow spiR8Ctl = 1 << 4 // SSPOL; CS line polarity
spiR8ClkActiveLow spiR8Ctl = 1 << 3 // POL; Clock line polarity
spiR8PHA spiR8Ctl = 1 << 2 // PHA; Phase 1 if set (leading edge for setup data)
spiR8Master spiR8Ctl = 1 << 1 // MODE; Slave mode if not set
spiR8Enable spiR8Ctl = 1 << 0 // EN; Enable mode
)
// SPI_CTL
// R8: Page 153-155. Default: 0x0002001C
type spiR8Ctl uint32
// SPI_INTCTL
// R8: Page 155-156.
type spiR8IntCtl uint32
const (
spiR8ClearInterrupt spiR8IntStatus = 1 << 31 // Clear interrupt busy flag
// 30:18 reserved
spiR8InvalidSS spiR8IntStatus = 1 << 17 // SSI
spiR8TC spiR8IntStatus = 1 << 16 // TC; Transfer Completed
)
// SPI_INT_STA
// R8: Page 156-157.
type spiR8IntStatus uint32
const (
// 31:13 reserved
spiR8DMATX3Quarter spiR8DMACtl = 1 << 12 // TXFIFO 3/4 empty
spiR8DMATX1Quarter spiR8DMACtl = 1 << 11 // TXFIFO 1/4 empty
spiR8DMATXByte spiR8DMACtl = 1 << 10 // TXFIFO Not Full
spiR8DMATXHalf spiR8DMACtl = 1 << 9 // TXFIFO 1/2 empty
spiR8DMATXEmpty spiR8DMACtl = 1 << 8 // TXFIFO empty
// 7:5 reserved
spiR8DMARX3Quarter spiR8DMACtl = 1 << 4 // RXFIFO 3/4 empty
spiR8DMARX1Quarter spiR8DMACtl = 1 << 3 // RXFIFO 1/4 empty
spiR8DMARXByte spiR8DMACtl = 1 << 2 // RXFIFO Not Full
spiR8DMARXHalf spiR8DMACtl = 1 << 1 // RXFIFO 1/2 empty
spiR8DMARXEmpty spiR8DMACtl = 1 << 0 // RXFIFO empty
)
// SPI_DMACTL
// R8: Page 158.
type spiR8DMACtl uint32
const (
// 31:13 reserved
spiR8DivRateSelect2 spiR8ClockCtl = 1 << 12 // DRS; Use spiDivXX if set, use mask otherwise
spiR8Div2 spiR8ClockCtl = 0 << 8 // CDR1; Use divisor 2^(n+1)
spiR8Div4 spiR8ClockCtl = 1 << 8 //
spiR8Div8 spiR8ClockCtl = 2 << 8 //
spiR8Div16 spiR8ClockCtl = 3 << 8 //
spiR8Div32 spiR8ClockCtl = 4 << 8 //
spiR8Div64 spiR8ClockCtl = 5 << 8 //
spiR8Div128 spiR8ClockCtl = 6 << 8 //
spiR8Div256 spiR8ClockCtl = 7 << 8 //
spiR8Div512 spiR8ClockCtl = 8 << 8 //
spiR8Div1024 spiR8ClockCtl = 9 << 8 //
spiR8Div2048 spiR8ClockCtl = 10 << 8 //
spiR8Div4096 spiR8ClockCtl = 11 << 8 //
spiR8Div8192 spiR8ClockCtl = 12 << 8 //
spiR8Div16384 spiR8ClockCtl = 13 << 8 //
spiR8Div32768 spiR8ClockCtl = 14 << 8 //
spiR8Div65536 spiR8ClockCtl = 15 << 8 //
spiR8Div1Mask spiR8ClockCtl = 0xFF // CDR2; Use divisor 2*(n+1)
)
// SPI_CCTL
// R8: Page 159.
type spiR8ClockCtl uint32
const (
// 31:25 reserved
spiR8FIFOTXShift = 16 // 0 to 64
// 15:7 reserved
spiR8FIFORXShift = 0 // 0 to 64
)
// SPI_FIFO_STA
// R8: Page 160.
type spiR8FIFOStatus uint32
func (s spiR8FIFOStatus) tx() uint8 {
return uint8((uint32(s) >> 16) & 127)
}
func (s spiR8FIFOStatus) rx() uint8 {
return uint8(uint32(s) & 127)
}
// spiR8Group is the mapping of SPI registers for one SPI controller.
// R8: Page 152-153.
type spiR8Group struct {
rx uint32 // 0x00 SPI_RX_DATA RX Data
tx uint32 // 0x04 SPI_TX_DATA TX Data
ctl spiR8Ctl // 0x08 SPI_CTL Control
intCtl spiR8IntCtl // 0x0C SPI_INTCTL Interrupt Control
status spiR8IntStatus // 0x10 SPI_ST Status
dmaCtl spiR8DMACtl // 0x14 SPI_DMACTL DMA Control
wait uint32 // 0x18 SPI_WAIT Clock Counter; 16 bits
clockCtl spiR8ClockCtl // 0x1C SPI_CCTL Clock Rate Control
burstCounter uint32 // 0x20 SPI_BC Burst Counter; 24 bits
transmitCounter uint32 // 0x24 SPI_TC Transmit Counter; 24 bits
fifoStatus spiR8FIFOStatus // 0x28 SPI_FIFO_STA FIFO Status
reserved [(0x1000 - 0x02C) / 4]uint32
}
func (s *spiR8Group) setup() {
s.intCtl = 0
s.status = 0
//s.dmaCtl = spiR8DMARXByte
s.dmaCtl = 0
s.wait = 2
s.clockCtl = spiR8DivRateSelect2 | spiR8Div1024
// spiR8DDMA
s.ctl = spiR8CSManual | spiR8LSB | spiR8Master | spiR8Enable
}
// spiMap is the mapping of SPI registers.
// R8: Page 152-153.
type spiMap struct {
groups [3]spiR8Group
}
// spi2Write do a write on SPI2_MOSI via polling.
func spi2Write(w []byte) error {
if drvDMA.clockMemory == nil || drvDMA.spiMemory == nil {
return errors.New("subsystem not initialized")
}
// Make sure the source clock is disabled. Set it at 250kHz.
//drvDMA.clockMemory.spi2Clk &^= clockSPIEnable
drvDMA.clockMemory.spi2Clk |= clockSPIEnable
drvDMA.clockMemory.spi2Clk = clockSPIDiv8a | clockSPIDiv12b
ch := &drvDMA.spiMemory.groups[2]
ch.setup()
fmt.Printf("Setup done\n")
for i := 0; i < len(w)/4; i++ {
// TODO(maruel): Access it in 8bit mode.
ch.tx = uint32(w[0])
for ch.fifoStatus.tx() == 0 {
log.Printf("Waiting for bit %# v\n", ch)
time.Sleep(time.Second)
}
}
fmt.Printf("Done\n")
return nil
}
// spi2Read do a read on SPI2_MISO via polling.
func spi2Read(r []byte) error {
if drvDMA.clockMemory == nil || drvDMA.spiMemory == nil {
return errors.New("subsystem not initialized")
}
// Make sure the source clock is disabled. Set it at 250kHz.
//drvDMA.clockMemory.spi2Clk &^= clockSPIEnable
drvDMA.clockMemory.spi2Clk |= clockSPIEnable
drvDMA.clockMemory.spi2Clk = clockSPIDiv8a | clockSPIDiv12b
ch := &drvDMA.spiMemory.groups[2]
ch.setup()
for i := 0; i < len(r)/4; i++ {
ch.tx = 0
for ch.status&spiR8TC == 0 {
}
// TODO(maruel): Access it in 8bit mode.
r[i] = uint8(ch.rx)
}
fmt.Printf("Done\n")
return nil
}