PKGBUILD/vendor/periph.io/x/periph/host/bcm283x/pcm.go
2018-12-07 20:42:30 +01:00

235 lines
8.9 KiB
Go

// Copyright 2017 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.
// pcm means I2S.
package bcm283x
import (
"errors"
"fmt"
"time"
"periph.io/x/periph/conn/physic"
)
type pcmCS uint32
// Pages 126-129
const (
// 31:26 reserved
pcmStandby pcmCS = 1 << 25 // STBY Allow at least 4 PCM clock cycles to take effect
pcmSync pcmCS = 1 << 24 // SYNC Two PCM clocks have occurred since last write
pcmRXSignExtend pcmCS = 1 << 23 // RXSEX Sign extend RXZ data
pcmRXFull pcmCS = 1 << 22 // RXF RX FIFO is full
pcmTXEmpty pcmCS = 1 << 21 // TXE TX FIFO is empty
pcmRXData pcmCS = 1 << 20 // RXD RX FIFO contains data
pcmTXData pcmCS = 1 << 19 // TXD TX FIFO ready to accept data
pcmRXR pcmCS = 1 << 18 // RXR RX FIFO needs reading
pcmTXW pcmCS = 1 << 17 // TXW TX FIFO needs writing
pcmRXErr pcmCS = 1 << 16 // RXERR RX FIFO error
pcmTXErr pcmCS = 1 << 15 // TXERR TX FIFO error
pcmRXSync pcmCS = 1 << 14 // RXSYNC RX FIFO is out of sync
pcmTXSync pcmCS = 1 << 13 // TXSYNC TX FIFO is out of sync
// 12:10 reserved
pcmDMAEnable pcmCS = 1 << 9 // DMAEN Generate TX&RX DMA DREQ
// 8:7 RXTHR controls when pcmRXR is set
pcmRXThresholdOne pcmCS = 0 << 7 // One sample in RX FIFO
pcmRXThreshold1 pcmCS = 1 << 7 // RX FIFO is at least (?) full
pcmRXThreshold2 pcmCS = 2 << 7 // ?
pcmRXThresholdFull pcmCS = 3 << 7 // RX is full
// 6:5 TXTHR controls when pcmTXW is set
pcmTXThresholdEmpty pcmCS = 0 << 5 // TX FIFO is empty
pcmTXThresholdNotFull1 pcmCS = 1 << 5 // At least one sample can be put
pcmTXThresholdNotFull2 pcmCS = 2 << 5 // At least one sample can be put
pcmTXThresholdOne pcmCS = 3 << 5 // One sample can be put
pcmRXClear pcmCS = 1 << 4 // RXCLR Clear RX FIFO; takes 2 PCM clock to take effect
pcmTXClear pcmCS = 1 << 3 // TXCLR Clear TX FIFO; takes 2 PCM clock to take effect
pcmTXEnable pcmCS = 1 << 2 // TXON Enable TX
pcmRXEnable pcmCS = 1 << 1 // RXON Enable FX
pcmEnable pcmCS = 1 << 0 // EN Enable the PCM
)
type pcmMode uint32
// Page 129-131
const (
// 31:29 reserved
pcmClockDisable pcmMode = 1 << 28 // CLK_DIS Cleanly disable the PCM clock
pcmDecimation32 pcmMode = 1 << 27 // PDMN; 0 is factor 16, 1 is factor 32
pcmRXPDMFilter pcmMode = 1 << 26 // PDME Enable input CIC filter on PDM input
pcmRXMerge pcmMode = 1 << 25 // FRXP Merge both channels as single FIFO entry
pcmTXMerge pcmMode = 1 << 24 // FTXP Merge both channels as singe FIFO entry
pcmClockSlave pcmMode = 1 << 23 // CLKM PCM CLK is input
pcmClockInverted pcmMode = 1 << 22 // CLKI Inverse clock signal
pcmFSSlave pcmMode = 1 << 21 // FSM PCM FS is input
pcmFSInverted pcmMode = 1 << 20 // FSI Invese FS signal
pcmFrameLengthShift = 10 //
pcmFrameLenghtMask pcmMode = 0x3F << pcmFrameLengthShift // FLEN Frame length + 1
pcmFSLenghtMask pcmMode = 0x3F << 0 // FSLEN FS pulse clock width
)
type pcmRX uint32
// Page 131-132
const (
pcmRX1Width pcmRX = 1 << 31 // CH1WEX Legacy
pcmRX1Enable pcmRX = 1 << 30 // CH1EN
pcmRX1PosShift = 20
pcmRX1PosMask pcmRX = 0x3F << pcmRX1PosShift // CH1POS Clock delay
pcmRX1Channel16 pcmRX = 8 << 16 // CH1WID (Arbitrary width between 8 and 16 is supported)
pcmRX2Width pcmRX = 1 << 15 // CH2WEX Legacy
pcmRX2Enable pcmRX = 1 << 14 // CH2EN
pcmRX2PosShift = 4
pcmRX2PosMask pcmRX = 0x3F << pcmRX2PosShift // CH2POS Clock delay
pcmRX2Channel16 pcmRX = 8 << 0 // CH2WID (Arbitrary width between 8 and 16 is supported)
)
type pcmTX uint32
// Page 133-134
const (
pcmTX1Width pcmTX = 1 << 31 // CH1WX Legacy
pcmTX1Enable pcmTX = 1 << 30 // CH1EN Enable channel 1
pcmTX1PosShift = 20
pcmTX1PosMask pcmTX = 0x3F << pcmTX1PosShift // CH1POS Clock delay
pcmTX1Channel16 pcmTX = 8 << 16 // CH1WID (Arbitrary width between 8 and 16 is supported)
pcmTX2Width pcmTX = 1 << 15 // CH2WEX Legacy
pcmTX2Enable pcmTX = 1 << 14 // CH2EN
pcmTX2PosShift = 4
pcmTX2PosMask pcmTX = 0x3F << pcmTX2PosShift // CH2POS Clock delay
pcmTX2Channel16 pcmTX = 8 << 0 // CH2WID (Arbitrary width between 8 and 16 is supported)
)
type pcmDreq uint32
// Page 134-135
const (
// 31 reserved
pcmDreqTXPanicShift = 24
pcmDreqTXPanicMask pcmDreq = 0x7F << pcmDreqTXPanicShift // TX_PANIC Panic level
// 23 reserved
pcmDreqRXPanicShift = 16
pcmDreqRXPanicMask pcmDreq = 0x7F << pcmDreqRXPanicShift // RX_PANIC Panic level
// 15 reserved
pcmDreqTXLevelShift = 8
pcmDreqTXLevelMask pcmDreq = 0x7F << pcmDreqTXPanicShift // TX Request Level
// 7 reserved
pcmDreqRXLevelShift = 0
pcmDreqRXLevelMask pcmDreq = 0x7F << pcmDreqRXPanicShift // RX Request Level
)
type pcmInterrupt uint32
// Page 135
const (
// 31:4 reserved
pcmIntRXErr pcmInterrupt = 1 << 3 // RXERR RX error interrupt enable
pcmIntTXErr pcmInterrupt = 1 << 2 // TXERR TX error interrupt enable
pcmIntRXEnable pcmInterrupt = 1 << 1 // RXR RX Read interrupt enable
pcmIntTXEnable pcmInterrupt = 1 << 0 // TXW TX Write interrupt enable
)
type pcmIntStatus uint32
// Page 135-136
const (
// 31:4 reserved
pcmIntStatRXErr pcmIntStatus = 1 << 3 // RXERR RX error occurred / clear
pcmIntStatTXErr pcmIntStatus = 1 << 2 // TXERR TX error occurred / clear
pcmIntStatRXEnable pcmIntStatus = 1 << 1 // RXR RX Read interrupt occurred / clear
pcmIntStatTXEnable pcmIntStatus = 1 << 0 // TXW TX Write interrupt occurred / clear
pcmIntStatusClear pcmIntStatus = 0xF
)
// pcmGray puts it into a special data/strobe mode that is under 'best effort'
// contract.
type pcmGray uint32
// Page 136-137
const (
// 31:22 reserved
pcmGrayRXFIFOLevelShift = 16
pcmGrayRXFIFOLevelMask pcmGray = 0x3F << pcmGrayRXFIFOLevelShift // RXFIFOLEVEL How many words in RXFIFO
pcmGrayFlushShift = 10
pcmGrayFlushMask = 0x3F << pcmGrayFlushShift // FLUSHED How many bits were valid when flush occurred
pcmGrayRXLevelShift = 4
pcmGrayRXLevelMask pcmGray = 0x3F << pcmGrayRXLevelShift // RXLEVEL How many GRAY coded bits received
pcmGrayFlush pcmGray = 1 << 2 // FLUSH
pcmGrayClear pcmGray = 1 << 1 // CLR
pcmGrayEnable pcmGray = 1 << 0 // EN
)
// Page 119
type pcmMap struct {
cs pcmCS // CS_A Control Status
fifo uint32 // FIFO_A FIFO register
mode pcmMode // MODE_A Operation mode
rxc pcmRX // RXC_A RX control
txc pcmTX // TXC_A TX control
dreq pcmDreq // DREQ_A DMA control
inten pcmInterrupt // INTEN_A Interrupt enable
intstc pcmIntStatus // INTSTC_A Interrupt status
gray pcmGray // GRAY Gray mode input processing
}
func (p *pcmMap) GoString() string {
return fmt.Sprintf(
"{\n cs: 0x%x,\n mode: 0x%x,\n rxc: 0x%x,\n txc: 0x%x,\n dreq: 0x%x,\n inten: 0x%x,\n intstc: 0x%x,\n gray: 0x%x,\n}",
p.cs, p.mode, p.rxc, p.txc, p.dreq, p.inten, p.intstc, p.gray)
}
func (p *pcmMap) reset() {
p.cs = 0
// In theory need to wait the equivalent of 2 PCM clocks.
// TODO(maruel): Use pcmSync busy loop to synchronize.
Nanospin(time.Microsecond)
// Hard reset
p.fifo = 0
p.mode = 0
p.rxc = 0
p.txc = 0
p.dreq = 0
p.inten = 0
p.intstc = pcmIntStatusClear
p.gray = 0
// Clear pcmStandby / pcm
}
// set initializes 8 bits stream via DMA with no delay and no FS.
func (p *pcmMap) set() {
p.cs |= pcmEnable
p.txc = pcmTX1Width | pcmTX1Channel16 | pcmTX1Enable // 32bit TX
p.mode = (32 - 1) << pcmFrameLengthShift
p.cs |= pcmTXClear | pcmRXClear
// In theory need to wait the equivalent of 2 PCM clocks.
// TODO(maruel): Use pcmSync busy loop to synchronize.
Nanospin(time.Microsecond)
p.dreq = 0x10<<pcmDreqTXPanicShift | 0x30<<pcmDreqTXLevelShift
p.cs |= pcmDMAEnable
// pcmTXThresholdOne ?
p.cs |= pcmTXEnable
}
// setPCMClockSource sets the PCM clock.
//
// It may select an higher frequency than the one requested.
//
// Other potentially good clock sources are PWM, SPI and UART.
func setPCMClockSource(f physic.Frequency) (physic.Frequency, uint32, error) {
if drvDMA.pcmMemory == nil {
return 0, 0, errors.New("subsystem PCM not initialized")
}
if drvDMA.clockMemory == nil {
return 0, 0, errors.New("subsystem Clock not initialized")
}
actual, divs, err := drvDMA.clockMemory.pcm.set(f, 1)
if err == nil {
drvDMA.pcmMemory.cs = 0
}
// Convert divisor into wait cycles.
return actual, divs, err
}