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
|
|||
|
}
|