208 lines
7.1 KiB
Go
208 lines
7.1 KiB
Go
// 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
|
||
}
|