First implementation

This commit is contained in:
2019-12-14 11:56:22 +01:00
parent a13838dbc5
commit be6a9c6f73
1060 changed files with 326870 additions and 0 deletions

220
vendor/periph.io/x/periph/host/allwinner/a20.go generated vendored Normal file
View File

@ -0,0 +1,220 @@
// Copyright 2018 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.
// This file contains pin mapping information that is specific to the Allwinner
// A20 model.
package allwinner
import (
"strings"
"periph.io/x/periph/conn/pin"
"periph.io/x/periph/host/sysfs"
)
// mappingA20 describes the mapping of the A20 processor gpios to their
// alternate functions.
//
// It omits the in & out functions which are available on all gpio.
//
// The mapping comes from the datasheet page 241:
// http://dl.linux-sunxi.org/A20/A20%20User%20Manual%202013-03-22.pdf
var mappingA20 = map[string][5]pin.Func{
"PA0": {"ERXD3", "SPI1_CS0", "UART2_RTS", "GRXD3"},
"PA1": {"ERXD2", "SPI1_CLK", "UART2_CTS", "GRXD2"},
"PA2": {"ERXD1", "SPI1_MOSI", "UART2_TX", "GRXD1"},
"PA3": {"ERXD0", "SPI1_MISO", "UART2_RX", "GRXD0"},
"PA4": {"ETXD3", "SPI1_CS1", "", "GTXD3"},
"PA5": {"ETXD2", "SPI3_CS0", "", "GTXD2"},
"PA6": {"ETXD1", "SPI3_CLK", "", "GTXD1"},
"PA7": {"ETXD0", "SPI3_MOSI", "", "GTXD0"},
"PA8": {"ERXCK", "SPI3_MISO", "", "CRXCK"},
"PA9": {"ERXERR", "SPI3_CS1", "", "GNULL", "I2S1_MCLK"},
"PA10": {"ERXDV", "", "UART1_TX", "GRXCTL"},
"PA11": {"EMDC", "", "UART1_RX", "GMDC"},
"PA12": {"EMDIO", "UART6_TX", "UART1_RTS", "GMDIO"},
"PA13": {"ETXEN", "UART6_RX", "UART1_CTS", "GTXCTL"},
"PA14": {"ETXCK", "UART7_TX", "UART1_DTR", "GNULL", "I2S1_SCK"},
"PA15": {"ECRS", "UART7_RX", "UART1_DSR", "GTXCK", "I2S1_WS"},
"PA16": {"ECOL", "CAN_TX", "UART1_DCD", "GCLKIN", "I2S1_DOUT"},
"PA17": {"ETXERR", "CAN_RX", "UART1_RI", "GNULL", "I2S1_DIN"},
"PB0": {"I2C0_SCL"},
"PB1": {"I2C0_SDA"},
"PB2": {"PWM0"},
"PB3": {"IR0_TX", "", "SPDIF_MCLK", "", "STANBYWFI"},
"PB4": {"IR0_RX"},
"PB5": {"I2S0_MCLK", "AC97_MCLK"},
"PB6": {"I2S0_SCK", "AC97_SCK"},
"PB7": {"I2S0_WS", "AC97_SYNC"},
"PB8": {"I2S0_DOUT0", "AC97_DOUT"},
"PB9": {"I2S0_DOUT1"},
"PB10": {"I2S0_DOUT2"},
"PB11": {"I2S0_DOUT3"},
"PB12": {"I2S0_DIN", "AC97_DI", "SPDIF_DI"},
"PB13": {"SPI2_CS1", "", "SPDIF_DO"},
"PB14": {"SPI2_CS0", "JTAG0_TMS"},
"PB15": {"SPI2_CLK", "JTAG0_TCK"},
"PB16": {"SPI2_MOSI", "JTAG0_TDO"},
"PB17": {"SPI2_MISO", "JTAG0_TDI"},
"PB18": {"I2C1_SCL"},
"PB19": {"I2C1_SDA"},
"PB20": {"I2C2_SCL"},
"PB21": {"I2C2_SDA"},
"PB22": {"UART0_TX", "IR1_TX"},
"PB23": {"UART0_RX", "IR1_RX"},
"PC0": {"NWE#", "SPI0_MOSI"},
"PC1": {"NALE", "SPI0_MISO"},
"PC2": {"NCLE", "SPI0_CLK"},
"PC3": {"NCE1"},
"PC4": {"NCE0"},
"PC5": {"NRE#"},
"PC6": {"NRB0", "SDC2_CMD"},
"PC7": {"NRB1", "SDC2_CLK"},
"PC8": {"NDQ0", "SDC2_D0"},
"PC9": {"NDQ1", "SDC2_D1"},
"PC10": {"NDQ2", "SDC2_D2"},
"PC11": {"NDQ3", "SDC2_D3"},
"PC12": {"NDQ4"},
"PC13": {"NDQ5"},
"PC14": {"NDQ6"},
"PC15": {"NDQ7"},
"PC16": {"NWP"},
"PC17": {"NCE2"},
"PC18": {"NCE3"},
"PC19": {"NCE4", "SPI2_CS0", "", "", "PC_EINT12"},
"PC20": {"NCE5", "SPI2_CLK", "", "", "PC_EINT13"},
"PC21": {"NCE6", "SPI2_MOSI", "", "", "PC_EINT14"},
"PC22": {"NCE7", "SPI2_MISO", "", "", "PC_EINT15"},
"PC23": {"", "SPI2_CS0"},
"PC24": {"NDQS"},
"PD0": {"LCD0_D0", "LVDS0_VP0"},
"PD1": {"LCD0_D1", "LVDS0_VN0"},
"PD2": {"LCD0_D2", "LVDS0_VP1"},
"PD3": {"LCD0_D3", "LVDS0_VN1"},
"PD4": {"LCD0_D4", "LVDS0_VP2"},
"PD5": {"LCD0_D5", "LVDS0_VN2"},
"PD6": {"LCD0_D6", "LVDS0_VPC"},
"PD7": {"LCD0_D7", "LVDS0_VNC"},
"PD8": {"LCD0_D8", "LVDS0_VP3"},
"PD9": {"LCD0_D9", "LVDS0_VN3"},
"PD10": {"LCD0_D10", "LVDS1_VP0"},
"PD11": {"LCD0_D11", "LVDS1_VN0"},
"PD12": {"LCD0_D12", "LVDS1_VP1"},
"PD13": {"LCD0_D13", "LVDS1_VN1"},
"PD14": {"LCD0_D14", "LVDS1_VP2"},
"PD15": {"LCD0_D15", "LVDS1_VN2"},
"PD16": {"LCD0_D16", "LVDS1_VPC"},
"PD17": {"LCD0_D17", "LVDS1_VNC"},
"PD18": {"LCD0_D18", "LVDS1_VP3"},
"PD19": {"LCD0_D19", "LVDS1_VN3"},
"PD20": {"LCD0_D20", "CSI1_MCLK"},
"PD21": {"LCD0_D21", "SMC_VPPEN"},
"PD22": {"LCD0_D22", "SMC_VPPPP"},
"PD23": {"LCD0_D23", "SMC_DET"},
"PD24": {"LCD0_CLK", "SMC_VCCEN"},
"PD25": {"LCD0_DE", "SMC_RST"},
"PD26": {"LCD0_HSYNC", "SMC_SLK"},
"PD27": {"LCD0_VSYNC", "SMC_SDA"},
"PE0": {"TS0_CLK", "CSI0_PCLK"},
"PE1": {"TS0_ERR", "CSI0_MCLK"},
"PE2": {"TS0_SYNC", "CSI0_HSYNC"},
"PE3": {"TS0_DLVD", "CSI0_VSYNC"},
"PE4": {"TS0_D0", "CSI0_D0"},
"PE5": {"TS0_D1", "CSI0_D1"},
"PE6": {"TS0_D2", "CSI0_D2"},
"PE7": {"TS0_D3", "CSI0_D3"},
"PE8": {"TS0_D4", "CSI0_D4"},
"PE9": {"TS0_D5", "CSI0_D5"},
"PE10": {"TS0_D6", "CSI0_D6"},
"PE11": {"TS0_D7", "CSI0_D7"},
"PF0": {"SDC0_D1", "", "JTAG1_TMS"},
"PF1": {"SDC0_D0", "", "JTAG1_TDI"},
"PF2": {"SDC0_CLK", "", "UART0_TX"},
"PF3": {"SDC0_CMD", "", "JTAG1_TDO"},
"PF4": {"SDC0_D3", "", "UART0_RX"},
"PF5": {"SDC0_D2", "", "JTAG1_TCK"},
"PG0": {"TS1_CLK", "CSI1_PCLK", "SDC1_CMD"},
"PG1": {"TS1_ERR", "CSI1_MCLK", "SDC1_CLK"},
"PG2": {"TS1_SYNC", "CSI1_HSYNC", "SDC1_D0"},
"PG3": {"TS1_DVLD", "CSI1_VSYNC", "SDC1_D1"},
"PG4": {"TS1_D0", "CSI1_D0", "SDC1_D2", "CSI0_D8"},
"PG5": {"TS1_D1", "CSI1_D1", "SDC1_D3", "CSI0_D9"},
"PG6": {"TS1_D2", "CSI1_D2", "UART3_TX", "CSI0_D10"},
"PG7": {"TS1_D3", "CSI1_D3", "UART3_RX", "CSI0_D11"},
"PG8": {"TS1_D4", "CSI1_D4", "UART3_RTS", "CSI0_D12"},
"PG9": {"TS1_D5", "CSI1_D4", "UART3_CTS", "CSI0_D13"},
"PG10": {"TS1_D6", "CSI1_D6", "UART4_TX", "CSI0_D14"},
"PG11": {"TS1_D7", "CSI1_D7", "UART4_RX", "CSI0_D15"},
"PH0": {"LCD1_D0", "", "UART3_TX", "", "PH_EINT0"},
"PH1": {"LCD1_D1", "", "UART3_RX", "", "PH_EINT1"},
"PH2": {"LCD1_D2", "", "UART3_RTS", "", "PH_EINT2"},
"PH3": {"LCD1_D3", "", "UART3_CTS", "", "PH_EINT3"},
"PH4": {"LCD1_D4", "", "UART4_TX", "", "PH_EINT4"},
"PH5": {"LCD1_D5", "", "UART4_RX", "", "PH_EINT5"},
"PH6": {"LCD1_D6", "", "UART5_TX", "MS_BS", "PH_EINT6"},
"PH7": {"LCD1_D7", "", "UART5_RX", "MS_CLK", "PH_EINT7"},
"PH8": {"LCD1_D8", "ERXD3", "KP_IN0", "MS_D0", "PH_EINT8"},
"PH9": {"LCD1_D9", "ERXD2", "KP_IN1", "MS_D1", "PH_EINT9"},
"PH10": {"LCD1_D10", "ERXD1", "KP_IN2", "MS_D2", "PH_EINT10"},
"PH11": {"LCD1_D11", "ERXD0", "KP_IN3", "MS_D3", "PH_EINT11"},
"PH12": {"LCD1_D12", "", "PS2_SCK1", "", "PH_EINT12"},
"PH13": {"LCD1_D13", "", "PS2_SDA1", "SMC_RST", "PH_EINT13"},
"PH14": {"LCD1_D14", "ETXD3", "KP_IN4", "SMC_VPPEN", "PH_EINT14"},
"PH15": {"LCD1_D15", "ETXD2", "KP_IN5", "SMC_VPPPP", "PH_EINT15"},
"PH16": {"LCD1_D16", "ETXD1", "KP_IN6", "SMC_DET", "PH_EINT16"},
"PH17": {"LCD1_D17", "ETXD0", "KP_IN7", "SMC_VCCEN", "PH_EINT17"},
"PH18": {"LCD1_D18", "ERXCK", "KP_OUT0", "SMC_SLK", "PH_EINT18"},
"PH19": {"LCD1_D19", "ERXERR", "KP_OUT1", "SMC_SDA", "PH_EINT19"},
"PH20": {"LCD1_D20", "ERXDV", "CAN_TX", "", "PH_EINT20"},
"PH21": {"LCD1_D21", "EMDC", "CAN_RX", "", "PH_EINT21"},
"PH22": {"LCD1_D22", "EMDIO", "KP_OUT2", "SDC1_CMD", ""},
"PH23": {"LCD1_D23", "ETXEN", "KP_OUT3", "SDC1_CLK", ""},
"PH24": {"LCD1_CLK", "ETXCK", "KP_OUT4", "SDC1_D0", ""},
"PH25": {"LCD1_DE", "ECRS", "KP_OUT5", "SDC1_D1", ""},
"PH26": {"LCD1_HSYNC", "ECOL", "KP_OUT6", "SDC1_D2", ""},
"PH27": {"LCD1_VSYNC", "ETXERR", "KP_OUT7", "SDC1_D3", ""},
"PI0": {"", "I2C3_SCL"},
"PI1": {"", "I2C3_SDA"},
"PI2": {"", "I2C4_SCL"},
"PI3": {"PWM1", "I2C4_SDA"},
"PI4": {"SDC3_CMD"},
"PI5": {"SDC3_CLK"},
"PI6": {"SDC3_D0"},
"PI7": {"SDC3_D1"},
"PI8": {"SDC3_D2"},
"PI9": {"SDC3_D3"},
"PI10": {"SPI0_CS0", "UART5_TX", "", "PI_EINT22"},
"PI11": {"SPI0_CLK", "UART5_RX", "", "PI_EINT23"},
"PI12": {"SPI0_MOSI", "UART6_TX", "CLK_OUT_A", "PI_EINT24"},
"PI13": {"SPI0_MISO", "UART6_RX", "CLK_OUT_B", "PI_EINT25"},
"PI14": {"SPI0_CS0", "PS2_SCK1", "TCLKIN0", "PI_EINT26"},
"PI15": {"SPI1_CS1", "PS2_SDA1", "TCLKIN1", "PI_EINT27"},
"PI16": {"SPI1_CS0", "UART2_RTS", "", "PI_EINT28"},
"PI17": {"SPI1_CLK", "UART2_CTS", "", "PI_EINT29"},
"PI18": {"SPI1_MOSI", "UART2_TX", "", "PI_EINT30"},
"PI19": {"SPI1_MISO", "UART2_RX", "", "PI_EINT31"},
"PI20": {"PS2_SCK0", "UART7_TX", "HSCL"},
"PI21": {"PS2_SDA0", "UART7_RX", "HSDA"},
}
// mapA20Pins uses mappingA20 to actually set the altFunc fields of all gpio
// and mark them as available.
//
// It is called by the generic allwinner processor code if an A20 is detected.
func mapA20Pins() error {
for name, altFuncs := range mappingA20 {
pin := cpupins[name]
pin.altFunc = altFuncs
pin.available = true
if strings.Contains(string(altFuncs[4]), "_EINT") ||
strings.Contains(string(altFuncs[3]), "_EINT") {
pin.supportEdge = true
}
// Initializes the sysfs corresponding pin right away.
pin.sysfsPin = sysfs.Pins[pin.Number()]
}
return nil
}

174
vendor/periph.io/x/periph/host/allwinner/a64.go generated vendored Normal file
View File

@ -0,0 +1,174 @@
// 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.
// This file contains pin mapping information that is specific to the Allwinner
// A64 model.
package allwinner
import (
"strings"
"periph.io/x/periph/conn/pin"
"periph.io/x/periph/host/sysfs"
)
// A64 specific pins.
var (
X32KFOUT *pin.BasicPin // Clock output of 32Khz crystal
KEY_ADC *pin.BasicPin // 6 bits resolution ADC for key application; can work up to 250Hz conversion rate; reference voltage is 2.0V
EAROUTP *pin.BasicPin // Earpiece amplifier negative differential output
EAROUTN *pin.BasicPin // Earpiece amplifier positive differential output
)
//
func init() {
X32KFOUT = &pin.BasicPin{N: "X32KFOUT"}
// BUG(maruel): These need to be converted to an analog.PinIO implementation
// once analog support is implemented.
KEY_ADC = &pin.BasicPin{N: "KEY_ADC"}
EAROUTP = &pin.BasicPin{N: "EAROUTP"}
EAROUTN = &pin.BasicPin{N: "EAROUTN"}
}
// mappingA64 describes the mapping of the A64 processor gpios to their
// alternate functions.
//
// It omits the in & out functions which are available on all gpio.
//
// The mapping comes from the datasheet page 23:
// http://files.pine64.org/doc/datasheet/pine64/A64_Datasheet_V1.1.pdf
//
// - The datasheet uses TWI instead of I2C but it is renamed here for
// consistency.
// - AIF is an audio interface, i.e. to connect to S/PDIF.
// - RGMII means Reduced gigabit media-independent interface.
// - SDC means SDCard?
// - NAND connects to a NAND flash controller.
// - CSI and CCI are for video capture.
var mappingA64 = map[string][5]pin.Func{
"PB0": {"UART2_TX", "", "JTAG0_TMS", "", "PB_EINT0"},
"PB1": {"UART2_RX", "", "JTAG0_TCK", "SIM_PWREN", "PB_EINT1"},
"PB2": {"UART2_RTS", "", "JTAG0_TDO", "SIM_VPPEN", "PB_EINT2"},
"PB3": {"UART2_CTS", "I2S0_MCLK", "JTAG0_TDI", "SIM_VPPPP", "PB_EINT3"},
"PB4": {"AIF2_SYNC", "I2S0_WS", "", "SIM_CLK", "PB_EINT4"},
"PB5": {"AIF2_BCLK", "I2S0_SCK", "", "SIM_DATA", "PB_EINT5"},
"PB6": {"AIF2_DOUT", "I2S0_DOUT", "", "SIM_RST", "PB_EINT6"},
"PB7": {"AIF2_DIN", "I2S0_DIN", "", "SIM_DET", "PB_EINT7"},
"PB8": {"", "", "UART0_TX", "", "PB_EINT8"},
"PB9": {"", "", "UART0_RX", "", "PB_EINT9"},
"PC0": {"NAND_WE", "", "SPI0_MOSI"},
"PC1": {"NAND_ALE", "SDC2_DS", "SPI0_MISO"},
"PC2": {"NAND_CLE", "", "SPI0_CLK"},
"PC3": {"NAND_CE1", "", "SPI0_CS0"},
"PC4": {"NAND_CE0"},
"PC5": {"NAND_RE", "SDC2_CLK"},
"PC6": {"NAND_RB0", "SDC2_CMD"},
"PC7": {"NAND_RB1"},
"PC8": {"NAND_DQ0", "SDC2_D0"},
"PC9": {"NAND_DQ1", "SDC2_D1"},
"PC10": {"NAND_DQ2", "SDC2_D2"},
"PC11": {"NAND_DQ3", "SDC2_D3"},
"PC12": {"NAND_DQ4", "SDC2_D4"},
"PC13": {"NAND_DQ5", "SDC2_D5"},
"PC14": {"NAND_DQ6", "SDC2_D6"},
"PC15": {"NAND_DQ7", "SDC2_D7"},
"PC16": {"NAND_DQS", "SDC2_RST"},
"PD0": {"LCD_D2", "UART3_TX", "SPI1_CS0", "CCIR_CLK"},
"PD1": {"LCD_D3", "UART3_RX", "SPI1_CLK", "CCIR_DE"},
"PD2": {"LCD_D4", "UART4_TX", "SPI1_MOSI", "CCIR_HSYNC"},
"PD3": {"LCD_D5", "UART4_RX", "SPI1_MISO", "CCIR_VSYNC"},
"PD4": {"LCD_D6", "UART4_RTS", "", "CCIR_D0"},
"PD5": {"LCD_D7", "UART4_CTS", "", "CCIR_D1"},
"PD6": {"LCD_D10", "", "", "CCIR_D2"},
"PD7": {"LCD_D11", "", "", "CCIR_D3"},
"PD8": {"LCD_D12", "", "RGMII_RXD3", "CCIR_D4"},
"PD9": {"LCD_D13", "", "RGMII_RXD2", "CCIR_D5"},
"PD10": {"LCD_D14", "", "RGMII_RXD1"},
"PD11": {"LCD_D15", "", "RGMII_RXD0"},
"PD12": {"LCD_D18", "LVDS_VP0", "RGMII_RXCK"},
"PD13": {"LCD_D19", "LVDS_VN0", "RGMII_RXCT"},
"PD14": {"LCD_D20", "LVDS_VP1", "RGMII_RXER"},
"PD15": {"LCD_D21", "LVDS_VN1", "RGMII_TXD3", "CCIR_D6"},
"PD16": {"LCD_D22", "LVDS_VP2", "RGMII_TXD2", "CCIR_D7"},
"PD17": {"LCD_D23", "LVDS_VN2", "RGMII_TXD1"},
"PD18": {"LCD_CLK", "LVDS_VPC", "RGMII_TXD0"},
"PD19": {"LCD_DE", "LVDS_VNC", "RGMII_TXCK"},
"PD20": {"LCD_HSYNC", "LVDS_VP3", "RGMII_TXCT"},
"PD21": {"LCD_VSYNC", "LVDS_VN3", "RGMII_CLKI"},
"PD22": {"PWM0", "", "MDC"},
"PD23": {"", "", "MDIO"},
"PD24": {""},
"PE0": {"CSI_PCLK", "", "TS_CLK"},
"PE1": {"CSI_MCLK", "", "TS_ERR"},
"PE2": {"CSI_HSYNC", "", "TS_SYNC"},
"PE3": {"CSI_VSYNC", "", "TS_DVLD"},
"PE4": {"CSI_D0", "", "TS_D0"},
"PE5": {"CSI_D1", "", "TS_D1"},
"PE6": {"CSI_D2", "", "TS_D2"},
"PE7": {"CSI_D3", "", "TS_D3"},
"PE8": {"CSI_D4", "", "TS_D4"},
"PE9": {"CSI_D5", "", "TS_D5"},
"PE10": {"CSI_D6", "", "TS_D6"},
"PE11": {"CSI_D7", "", "TS_D7"},
"PE12": {"CSI_SCK"},
"PE13": {"CSI_SDA"},
"PE14": {"PLL_LOCK_DBG", "I2C2_SCL"},
"PE15": {"", "I2C2_SDA"},
"PE16": {""},
"PE17": {""},
"PF0": {"SDC0_D1", "JTAG1_TMS"},
"PF1": {"SDC0_D0", "JTAG1_TDI"},
"PF2": {"SDC0_CLK", "UART0_TX"},
"PF3": {"SDC0_CMD", "JTAG1_TDO"},
"PF4": {"SDC0_D3", "UART0_RX"},
"PF5": {"SDC0_D2", "JTAG1_TCK"},
"PF6": {""},
"PG0": {"SDC1_CLK", "", "", "", "PG_EINT0"},
"PG1": {"SDC1_CMD", "", "", "", "PG_EINT1"},
"PG2": {"SDC1_D0", "", "", "", "PG_EINT2"},
"PG3": {"SDC1_D1", "", "", "", "PG_EINT3"},
"PG4": {"SDC1_D2", "", "", "", "PG_EINT4"},
"PG5": {"SDC1_D3", "", "", "", "PG_EINT5"},
"PG6": {"UART1_TX", "", "", "", "PG_EINT6"},
"PG7": {"UART1_RX", "", "", "", "PG_EINT7"},
"PG8": {"UART1_RTS", "", "", "", "PG_EINT8"},
"PG9": {"UART1_CTS", "", "", "", "PG_EINT9"},
"PG10": {"AIF3_SYNC", "I2S1_WS", "", "", "PG_EINT10"},
"PG11": {"AIF3_BCLK", "I2S1_SCK", "", "", "PG_EINT11"},
"PG12": {"AIF3_DOUT", "I2S1_DOUT", "", "", "PG_EINT12"},
"PG13": {"AIF3_DIN", "I2S1_DIN", "", "", "PG_EINT13"},
"PH0": {"I2C0_SCL", "", "", "", "PH_EINT0"},
"PH1": {"I2C0_SDA", "", "", "", "PH_EINT1"},
"PH2": {"I2C1_SCL", "", "", "", "PH_EINT2"},
"PH3": {"I2C1_SDA", "", "", "", "PH_EINT3"},
"PH4": {"UART3_TX", "", "", "", "PH_EINT4"},
"PH5": {"UART3_RX", "", "", "", "PH_EINT5"},
"PH6": {"UART3_RTS", "", "", "", "PH_EINT6"},
"PH7": {"UART3_CTS", "", "", "", "PH_EINT7"},
"PH8": {"OWA_OUT", "", "", "", "PH_EINT8"},
"PH9": {"", "", "", "", "PH_EINT9"},
"PH10": {"MIC_CLK", "", "", "", "PH_EINT10"},
"PH11": {"MIC_DATA", "", "", "", "PH_EINT11"},
}
// mapA64Pins uses mappingA64 to actually set the altFunc fields of all gpio
// and mark them as available.
//
// It is called by the generic allwinner processor code if an A64 is detected.
func mapA64Pins() error {
for name, altFuncs := range mappingA64 {
pin := cpupins[name]
pin.altFunc = altFuncs
pin.available = true
if strings.Contains(string(altFuncs[4]), "_EINT") {
pin.supportEdge = true
}
// Initializes the sysfs corresponding pin right away.
pin.sysfsPin = sysfs.Pins[pin.Number()]
}
return nil
}

View File

@ -0,0 +1,7 @@
// 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
const isArm = true

View File

@ -0,0 +1,9 @@
// 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.
// +build arm64
package allwinner
const isArm = true

View File

@ -0,0 +1,9 @@
// 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.
// +build !arm,!arm64
package allwinner
const isArm = false

281
vendor/periph.io/x/periph/host/allwinner/clock.go generated vendored Normal file
View File

@ -0,0 +1,281 @@
// 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
const (
clockSPIEnable clockSPI = 1 << 31 // SCLK_GATING
// 30:26 reserved
clockSPIOSC24M clockSPI = 0 << 24 // CLK_SRC_SEL
clockSPIPLL6 clockSPI = 1 << 24 // A64: PLL_PERIPH0(1X)
clockSPIPLL5 clockSPI = 2 << 24 // A64: PLL_PERIPH1(1X) R8: PLL5 = DDR
// 23:18 reserved
clockSPIDiv1a clockSPI = 0 << 16 // CLK_DIV_RATIO_N
clockSPIDiv2a clockSPI = 1 << 16 //
clockSPIDiv4a clockSPI = 2 << 16 //
clockSPIDiv8a clockSPI = 3 << 16 //
// 15:4 reserved
clockSPIDiv1b clockSPI = 0 << 0 // CLK_DIV_RATIO_M
clockSPIDiv2b clockSPI = 1 << 0 //
clockSPIDiv3b clockSPI = 2 << 0 //
clockSPIDiv4b clockSPI = 3 << 0 //
clockSPIDiv5b clockSPI = 4 << 0 //
clockSPIDiv6b clockSPI = 5 << 0 //
clockSPIDiv7b clockSPI = 6 << 0 //
clockSPIDiv8b clockSPI = 7 << 0 //
clockSPIDiv9b clockSPI = 8 << 0 //
clockSPIDiv10b clockSPI = 9 << 0 //
clockSPIDiv11b clockSPI = 10 << 0 //
clockSPIDiv12b clockSPI = 11 << 0 //
clockSPIDiv13b clockSPI = 12 << 0 //
clockSPIDiv14b clockSPI = 13 << 0 //
clockSPIDiv15b clockSPI = 14 << 0 //
clockSPIDiv16b clockSPI = 15 << 0 //
)
// Also valid for IR.
//
// SPI0_SCLK_CFG_REG / SPI1_SCLK_CFG_REG / SPI2_SCLK_CFG_REG / IR_SCLK_CFG_REG
//
// A64: Page 110-111. (Also Page 554?)
// R8: Page 71.
type clockSPI uint32
const (
clockPLL6Enable clockPLL6R8Ctl = 1 << 31 // PLL6_Enable
clockPLL6Force24Mhz clockPLL6R8Ctl = 1 << 30 // PLL6_BYPASS_EN; force 24Mhz
// 29:13 reserved
clockPLL6FactorMulN0 clockPLL6R8Ctl = 0 << 8 // PLL6_FACTOR_N
clockPLL6FactorMulN1 clockPLL6R8Ctl = 1 << 8 //
clockPLL6FactorMulN2 clockPLL6R8Ctl = 2 << 8 //
clockPLL6FactorMulN3 clockPLL6R8Ctl = 3 << 8 //
clockPLL6FactorMulN4 clockPLL6R8Ctl = 4 << 8 //
clockPLL6FactorMulN5 clockPLL6R8Ctl = 5 << 8 //
clockPLL6FactorMulN6 clockPLL6R8Ctl = 6 << 8 //
clockPLL6FactorMulN7 clockPLL6R8Ctl = 7 << 8 //
clockPLL6FactorMulN8 clockPLL6R8Ctl = 8 << 8 //
clockPLL6FactorMulN9 clockPLL6R8Ctl = 9 << 8 //
clockPLL6FactorMulN10 clockPLL6R8Ctl = 10 << 8 //
clockPLL6FactorMulN11 clockPLL6R8Ctl = 11 << 8 //
clockPLL6FactorMulN12 clockPLL6R8Ctl = 12 << 8 //
clockPLL6FactorMulN13 clockPLL6R8Ctl = 13 << 8 //
clockPLL6FactorMulN14 clockPLL6R8Ctl = 14 << 8 //
clockPLL6FactorMulN15 clockPLL6R8Ctl = 15 << 8 //
clockPLL6FactorMulN16 clockPLL6R8Ctl = 16 << 8 //
clockPLL6FactorMulN17 clockPLL6R8Ctl = 17 << 8 //
clockPLL6FactorMulN18 clockPLL6R8Ctl = 18 << 8 //
clockPLL6FactorMulN19 clockPLL6R8Ctl = 19 << 8 //
clockPLL6FactorMulN20 clockPLL6R8Ctl = 20 << 8 //
clockPLL6FactorMulN21 clockPLL6R8Ctl = 21 << 8 //
clockPLL6FactorMulN22 clockPLL6R8Ctl = 22 << 8 //
clockPLL6FactorMulN23 clockPLL6R8Ctl = 23 << 8 //
clockPLL6FactorMulN24 clockPLL6R8Ctl = 24 << 8 //
clockPLL6FactorMulN25 clockPLL6R8Ctl = 25 << 8 //
clockPLL6FactorMulN26 clockPLL6R8Ctl = 26 << 8 //
clockPLL6FactorMulN27 clockPLL6R8Ctl = 27 << 8 //
clockPLL6FactorMulN28 clockPLL6R8Ctl = 28 << 8 //
clockPLL6FactorMulN29 clockPLL6R8Ctl = 29 << 8 //
clockPLL6FactorMulN30 clockPLL6R8Ctl = 30 << 8 //
clockPLL6FactorMulN31 clockPLL6R8Ctl = 31 << 8 //
clockPLL6Damping clockPLL6R8Ctl = 2 << 6 //
clockPLL6FactorMulK1 clockPLL6R8Ctl = 0 << 4 // PLL6_FACTOR_K
clockPLL6FactorMulK2 clockPLL6R8Ctl = 1 << 4 //
clockPLL6FactorMulK3 clockPLL6R8Ctl = 2 << 4 //
clockPLL6FactorMulK4 clockPLL6R8Ctl = 3 << 4 //
// 3:2 reserved
clockPLL6FactorDivM1 clockPLL6R8Ctl = 0 << 4 // PLL6_FACTOR_M
clockPLL6FactorDivM2 clockPLL6R8Ctl = 1 << 4 //
clockPLL6FactorDivM3 clockPLL6R8Ctl = 2 << 4 //
clockPLL6FactorDivM4 clockPLL6R8Ctl = 3 << 4 //
)
// PLL6_CFG_REG
// R8: Page 63; default 0x21009931
//
// Output = (24MHz*N*K)/M/2
// Note: the output 24MHz*N*K clock must be in the range of 240MHz~3GHz if the
// bypass is disabled.
type clockPLL6R8Ctl uint32
// clockMap is the mapping of important registers across CPUs.
type clockMap struct {
reserved0 [0xA0 / 4]uint32 //
spi0Clk clockSPI // 0x0A0 SPI0_SCLK_CFG_REG SPI0 Clock
spi1Clk clockSPI // 0x0A4 SPI1_SCLK_CFG_REG SPI1 Clock
spi2Clk clockSPI // 0x0A8 SPI2_SCLK_CFG_REG SPI2 Clock (Not on A64)
}
// R8: Page 57-59.
type clockMapR8 struct {
r0 uint32 // 0x000 PLL1_CFG_REG PLL1 Control
r1 uint32 // 0x004 PLL1_TUN_REG PLL1 Tuning
r2 uint32 // 0x008 PLL2_CFG_REG PLL2 Control
r3 uint32 // 0x00C PLL2_TUN_REG PLL2 Tuning
r4 uint32 // 0x010 PLL3_CFG_REG PLL3 Control
r5 uint32 // 0x014
r6 uint32 // 0x018 PLL4_CFG_REG PLL4 Control
r7 uint32 // 0x01C
r8 uint32 // 0x020 PLL5_CFG_REG PLL5 Control
r9 uint32 // 0x024 PLL5_TUN_REG PLL5 Tuning
r10 clockPLL6R8Ctl // 0x028 PLL6_CFG_REG PLL6 Control
r11 uint32 // 0x02C PLL6 Tuning
r12 uint32 // 0x030 PLL7_CFG_REG
r13 uint32 // 0x034
r14 uint32 // 0x038 PLL1_TUN2_REG PLL1 Tuning2
r15 uint32 // 0x03C PLL5_TUN2_REG PLL5 Tuning2
r16 uint32 // 0x04C
r17 uint32 // 0x050 OSC24M_CFG_REG OSC24M control
r18 uint32 // 0x054 CPU_AHB_APB0_CFG_REG CPU, AHB And APB0 Divide Ratio
r19 uint32 // 0x058 APB1_CLK_DIV_REG APB1 Clock Divider
r20 uint32 // 0x05C AXI_GATING_REG AXI Module Clock Gating
r21 uint32 // 0x060 AHB_GATING_REG0 AHB Module Clock Gating 0
r22 uint32 // 0x064 AHB_GATING_REG1 AHB Module Clock Gating 1
r23 uint32 // 0x068 APB0_GATING_REG APB0 Module Clock Gating
r24 uint32 // 0x06C APB1_GATING_REG APB1 Module Clock Gating
r25 uint32 // 0x080 NAND_SCLK_CFG_REG Nand Flash Clock
r26 uint32 // 0x084
r27 uint32 // 0x088 SD0_SCLK_CFG_REG SD0 Clock
r28 uint32 // 0x08C SD1_SCLK_CFG_REG SD1 Clock
r29 uint32 // 0x090 SD2_SCLK_CFG_REG SD2 Clock
r30 uint32 // 0x094
r31 uint32 // 0x098
r32 uint32 // 0x09C CE_SCLK_CFG_REG Crypto Engine Clock
spi0Clk clockSPI // 0x0A0 SPI0_SCLK_CFG_REG SPI0 Clock
spi1Clk clockSPI // 0x0A4 SPI1_SCLK_CFG_REG SPI1 Clock
spi2Clk clockSPI // 0x0A8 SPI2_SCLK_CFG_REG SPI2 Clock
r33 uint32 // 0x0AC
irClk clockSPI // 0x0B0 IR_SCLK_CFG_REG IR Clock
r34 uint32 // 0x0B4
r35 uint32 // 0x0B8
r36 uint32 // 0x0BC
r37 uint32 // 0x0C0
r38 uint32 // 0x0C4
r39 uint32 // 0x0C8
r40 uint32 // 0x0CC
r41 uint32 // 0x0D0
r42 uint32 // 0x0D4
r43 uint32 // 0x100 DRAM_SCLK_CFG_REG DRAM Clock
r44 uint32 // 0x104 BE_CFG_REG Display Engine Backend Clock
r45 uint32 // 0x108
r46 uint32 // 0x10C FE_CFG_REG Display Engine Front End Clock
r47 uint32 // 0x110
r48 uint32 // 0x114
r49 uint32 // 0x118
r50 uint32 // 0x11C
r51 uint32 // 0x120
r52 uint32 // 0x124
r53 uint32 // 0x128
r54 uint32 // 0x12C LCD_CH1_CFG_REG LCD Channel1 Clock
r55 uint32 // 0x130
r56 uint32 // 0x134 CSI_CFG_REG CSI Clock
r57 uint32 // 0x138
r58 uint32 // 0x13C VE_CFG_REG Video Engine Clock
r59 uint32 // 0x140 AUDIO_CODEC_SCLK_CFG_REG Audio Codec Gating Special Clock
r60 uint32 // 0x144 AVS_SCLK_CFG_REG AVS Gating Special Clock
r61 uint32 // 0x148
r62 uint32 // 0x14C
r63 uint32 // 0x150
r64 uint32 // 0x154 MALI_CLOCK_CFG_REG Mali400 Gating Special Clock
r65 uint32 // 0x158
r66 uint32 // 0x15C MBUS_SCLK_CFG_REG MBUS Gating Clock
r67 uint32 // 0x160 IEP_SCLK_CFG_REG IEP Gating Clock
}
// A64: Page 81-84.
type clockMapA64 struct {
r0 uint32 // 0x000 PLL_CPUX_CTRL_REG PLL_CPUX Control Register
r1 uint32 // 0x008 PLL_AUDIO_CTRL_REG PLL_AUDIO Control Register
r2 uint32 // 0x010 PLL_VIDEO0_CTRL_REG PLL_VIDEO0 Control Register
r3 uint32 // 0x018 PLL_VE_CTRL_REG PLL_VE Control Register
r4 uint32 // 0x020 PLL_DDR0_CTRL_REG PLL_DDR0 Control Register
r5 uint32 // 0x028 PLL_PERIPH0_CTRL_REG PLL_PERIPH0 Control Register
r6 uint32 // 0x02C PLL_PERIPH1_CTRL_REG PLL_PERIPH1 Control Register
r7 uint32 // 0x030 PLL_VIDEO1_CTRL_REG PLL_VIDEO1 Control Register
r8 uint32 // 0x038 PLL_GPU_CTRL_REG PLL_GPU Control Register
r9 uint32 // 0x040 PLL_MIPI_CTRL_REG PLL_MIPI Control Register
r10 uint32 // 0x044 PLL_HSIC_CTRL_REG PLL_HSIC Control Register
r11 uint32 // 0x048 PLL_DE_CTRL_REG PLL_DE Control Register
r12 uint32 // 0x04C PLL_DDR1_CTRL_REG PLL_DDR1 Control Register
r13 uint32 // 0x050 CPU_AXI_CFG_REG CPUX/AXI Configuration Register
r14 uint32 // 0x054 AHB1_APB1_CFG_REG AHB1/APB1 Configuration Register
r15 uint32 // 0x058 APB2_CFG_REG APB2 Configuration Register
r16 uint32 // 0x05C AHB2_CFG_REG AHB2 Configuration Register
r17 uint32 // 0x060 BUS_CLK_GATING_REG0 Bus Clock Gating Register 0
r18 uint32 // 0x064 BUS_CLK_GATING_REG1 Bus Clock Gating Register 1
r19 uint32 // 0x068 BUS_CLK_GATING_REG2 Bus Clock Gating Register 2
r20 uint32 // 0x06C BUS_CLK_GATING_REG3 Bus Clock Gating Register 3
r21 uint32 // 0x070 BUS_CLK_GATING_REG4 Bus Clock Gating Register 4
r22 uint32 // 0x074 THS_CLK_REG THS Clock Register
r23 uint32 // 0x080 NAND_CLK_REG NAND Clock Register
r24 uint32 // 0x088 SDMMC0_CLK_REG SDMMC0 Clock Register
r25 uint32 // 0x08C SDMMC1_CLK_REG SDMMC1 Clock Register
r26 uint32 // 0x090 SDMMC2_CLK_REG SDMMC2 Clock Register
r27 uint32 // 0x098 TS_CLK_REG TS Clock Register
r28 uint32 // 0x09C CE_CLK_REG CE Clock Register
spi0Clk clockSPI // 0x0A0 SPI0_CLK_REG SPI0 Clock Register
spi1Clk clockSPI // 0x0A4 SPI1_CLK_REG SPI1 Clock Register
r29 uint32 // 0x0B0 I2S/PCM-0_CLK_REG I2S/PCM-0 Clock Register
r30 uint32 // 0x0B4 I2S/PCM-1_CLK_REG I2S/PCM-1 Clock Register
r31 uint32 // 0x0B8 I2S/PCM-2_CLK_REG I2S/PCM-2 Clock Register
r32 uint32 // 0x0C0 SPDIF_CLK_REG SPDIF Clock Register
r33 uint32 // 0x0CC USBPHY_CFG_REG USBPHY Configuration Register
r34 uint32 // 0x0F4 DRAM_CFG_REG DRAM Configuration Register
r35 uint32 // 0x0F8 PLL_DDR_CFG_REG PLL_DDR Configuration Register
r36 uint32 // 0x0FC MBUS_RST_REG MBUS Reset Register
r37 uint32 // 0x100 DRAM_CLK_GATING_REG DRAM Clock Gating Register
r38 uint32 // 0x104 DE_CLK_REG DE Clock Register
r39 uint32 // 0x118 TCON0_CLK_REG TCON0 Clock Register
r40 uint32 // 0x11C TCON1_CLK_REG TCON1 Clock Register
r41 uint32 // 0x124 DEINTERLACE_CLK_REG DEINTERLACE Clock Register
r42 uint32 // 0x130 CSI_MISC_CLK_REG CSI_MISC Clock Register
r43 uint32 // 0x134 CSI_CLK_REG CSI Clock Register
r44 uint32 // 0x13C VE_CLK_REG VE Clock Register
r45 uint32 // 0x140 AC_DIG_CLK_REG AC Digital Clock Register
r46 uint32 // 0x144 AVS_CLK_REG AVS Clock Register
r47 uint32 // 0x150 HDMI_CLK_REG HDMI Clock Register
r48 uint32 // 0x154 HDMI_SLOW_CLK_REG HDMI Slow Clock Register
r49 uint32 // 0x15C MBUS_CLK_REG MBUS Clock Register
r50 uint32 // 0x168 MIPI_DSI_CLK_REG MIPI_DSI Clock Register
r51 uint32 // 0x1A0 GPU_CLK_REG GPU Clock Register
r52 uint32 // 0x200 PLL_STABLE_TIME_REG0 PLL Stable Time Register0
r53 uint32 // 0x204 PLL_STABLE_TIME_REG1 PLL Stable Time Register1
r54 uint32 // 0x21C PLL_PERIPH1_BIAS_REG PLL_PERIPH1 Bias Register
r55 uint32 // 0x220 PLL_CPUX_BIAS_REG PLL_CPUX Bias Register
r56 uint32 // 0x224 PLL_AUDIO_BIAS_REG PLL_AUDIO Bias Register
r57 uint32 // 0x228 PLL_VIDEO0_BIAS_REG PLL_VIDEO0 Bias Register
r58 uint32 // 0x22C PLL_VE_BIAS_REG PLL_VE Bias Register
r59 uint32 // 0x230 PLL_DDR0_BIAS_REG PLL_DDR0 Bias Register
r60 uint32 // 0x234 PLL_PERIPH0_BIAS_REG PLL_PERIPH0 Bias Register
r61 uint32 // 0x238 PLL_VIDEO1_BIAS_REG PLL_VIDEO1 Bias Register
r62 uint32 // 0x23C PLL_GPU_BIAS_REG PLL_GPU Bias Register
r63 uint32 // 0x240 PLL_MIPI_BIAS_REG PLL_MIPI Bias Register
r64 uint32 // 0x244 PLL_HSIC_BIAS_REG PLL_HSIC Bias Register
r65 uint32 // 0x248 PLL_DE_BIAS_REG PLL_DE Bias Register
r66 uint32 // 0x24C PLL_DDR1_BIAS_REG PLL_DDR1 Bias Register
r67 uint32 // 0x250 PLL_CPUX_TUN_REG PLL_CPUX Tuning Register
r68 uint32 // 0x260 PLL_DDR0_TUN_REG PLL_DDR0 Tuning Register
r69 uint32 // 0x270 PLL_MIPI_TUN_REG PLL_MIPI Tuning Register
r70 uint32 // 0x27C PLL_PERIPH1_PAT_CTRL_REG PLL_PERIPH1 Pattern Control Register
r71 uint32 // 0x280 PLL_CPUX_PAT_CTRL_REG PLL_CPUX Pattern Control Register
r72 uint32 // 0x284 PLL_AUDIO_PAT_CTRL_REG PLL_AUDIO Pattern Control Register
r73 uint32 // 0x288 PLL_VIDEO0_PAT_CTRL_REG PLL_VIDEO0 Pattern Control Register
r74 uint32 // 0x28C PLL_VE_PAT_CTRL_REG PLL_VE Pattern Control Register
r75 uint32 // 0x290 PLL_DDR0_PAT_CTRL_REG PLL_DDR0 Pattern Control Register
r76 uint32 // 0x298 PLL_VIDEO1_PAT_CTRL_REG PLL_VIDEO1 Pattern Control Register
r77 uint32 // 0x29C PLL_GPU_PAT_CTRL_REG PLL_GPU Pattern Control Register
r78 uint32 // 0x2A0 PLL_MIPI_PAT_CTRL_REG PLL_MIPI Pattern Control Register
r79 uint32 // 0x2A4 PLL_HSIC_PAT_CTRL_REG PLL_HSIC Pattern Control Register
r80 uint32 // 0x2A8 PLL_DE_PAT_CTRL_REG PLL_DE Pattern Control Register
r81 uint32 // 0x2AC PLL_DDR1_PAT_CTRL_REG0 PLL_DDR1 Pattern Control Register0
r82 uint32 // 0x2B0 PLL_DDR1_PAT_CTRL_REG1 PLL_DDR1 Pattern Control Register1
r83 uint32 // 0x2C0 BUS_SOFT_RST_REG0 Bus Software Reset Register 0
r84 uint32 // 0x2C4 BUS_SOFT_RST_REG1 Bus Software Reset Register 1
r85 uint32 // 0x2C8 BUS_SOFT_RST_REG2 Bus Software Reset Register 2
r86 uint32 // 0x2D0 BUS_SOFT_RST_REG3 Bus Software Reset Register 3
r87 uint32 // 0x2D8 BUS_SOFT_RST_REG4 Bus Software Reset Register 4
r88 uint32 // 0x2F0 CCM_SEC_SWITCH_REG CCM Security Switch Register
r89 uint32 // 0x300 PS_CTRL_REG PS Control Register
r90 uint32 // 0x304 PS_CNT_REG PS Counter Register
r91 uint32 // 0x320 PLL_LOCK_CTRL_REG PLL Lock Control Register
}

98
vendor/periph.io/x/periph/host/allwinner/detect.go generated vendored Normal file
View File

@ -0,0 +1,98 @@
// 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 (
"strings"
"sync"
"periph.io/x/periph/host/distro"
)
// Present detects whether the host CPU is an Allwinner CPU.
//
// https://en.wikipedia.org/wiki/Allwinner_Technology
func Present() bool {
detection.do()
return detection.isAllwinner
}
// IsR8 detects whether the host CPU is an Allwinner R8 CPU.
//
// It looks for the string "sun5i-r8" in /proc/device-tree/compatible.
func IsR8() bool {
detection.do()
return detection.isR8
}
// IsA20 detects whether the host CPU is an Allwinner A20 CPU.
//
// It first looks for the string "sun71-a20" in /proc/device-tree/compatible,
// and if that fails it checks for "Hardware : sun7i" in /proc/cpuinfo.
func IsA20() bool {
detection.do()
return detection.isA20
}
// IsA64 detects whether the host CPU is an Allwinner A64 CPU.
//
// It looks for the string "sun50iw1p1" in /proc/device-tree/compatible.
func IsA64() bool {
detection.do()
return detection.isA64
}
//
type detectionS struct {
mu sync.Mutex
done bool
isAllwinner bool
isR8 bool
isA20 bool
isA64 bool
}
var detection detectionS
// do contains the CPU detection logic that determines whether we have an
// Allwinner CPU and if so, which exact model.
//
// Sadly there is no science behind this, it's more of a trial and error using
// as many boards and OS flavors as possible.
func (d *detectionS) do() {
d.mu.Lock()
defer d.mu.Unlock()
if !d.done {
d.done = true
if isArm {
for _, c := range distro.DTCompatible() {
if strings.Contains(c, "sun50iw1p1") {
d.isA64 = true
}
if strings.Contains(c, "sun5i-r8") {
d.isR8 = true
}
if strings.Contains(c, "sun7i-a20") {
d.isA20 = true
}
}
d.isAllwinner = d.isA64 || d.isR8 || d.isA20
if !d.isAllwinner {
// The kernel in the image that comes pre-installed on the pcDuino3 Nano
// is an old 3.x kernel that doesn't expose the device-tree in procfs,
// so do an extra check in cpuinfo as well if we haven't detected
// anything yet.
// Distros based on 4.x kernels do expose it.
if hw, ok := distro.CPUInfo()["Hardware"]; ok {
if hw == "sun7i" {
d.isA20 = true
}
}
}
}
}
}

474
vendor/periph.io/x/periph/host/allwinner/dma.go generated vendored Normal file
View File

@ -0,0 +1,474 @@
// 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.
// Unlike the bcm283x, the allwinner CPUs do not have a "clear bit" and "set
// bit" registers, they only have the data register. Also, allwinner CPUs do
// not support linked lists of DMA buffers. On the other hand, the Allwinner DMA
// controller supports 8 bits transfers instead of 32-128 bits that the bcm283x
// DMA controller supports.
//
// This means that only 8 bits can be used per sample, and only one stream is
// necessary. This results in 1/8th th memory usage than on the bcm283x. The
// drawback is that a block of 8 contiguous GPIO pins must be dedicated to the
// stream.
package allwinner
import (
"errors"
"fmt"
"log"
"os"
"periph.io/x/periph"
"periph.io/x/periph/host/pmem"
)
// dmaMap represents the DMA memory mapped CPU registers.
//
// This map is specific to the currently supported CPUs and will have to be
// adapted as more CPUs are supported. In particular the number of physical
// channels varies across different CPUs.
//
// Note that we modify the DMA controllers without telling the kernel driver.
// The driver keeps its own table of which DMA channel is available so this
// code could effectively crash the whole system. It practice this works.
// #everythingisfine
type dmaMap struct {
irqEn dmaR8Irq // DMA_IRQ_EN_REG
irqPendStas dmaR8PendingIrq // DMA_IRQ_PEND_STAS_REG
reserved0 [(0x100 - 8) / 4]uint32 //
normal [8]dmaR8NormalGroup // 0x100 The "8" "normal" DMA channels (only one active at a time so there's effectively one)
reserved1 [0x100 / 4]uint32 //
dedicated [8]dmaDedicatedGroup // 0x300 The 8 "dedicated" (as in actually existing) DMA channels
}
func (d *dmaMap) getDedicated() int {
for i := len(d.dedicated) - 1; i >= 0; i-- {
if d.dedicated[i].isAvailable() {
return i
}
}
return -1
}
// dmaNormalGroup is the control registers for the first block of 8 DMA
// controllers.
//
// They can be intentionally slowed down, unlike the dedicated DMA ones.
//
// The big caveat is that only one controller can be active at a time and the
// execution sequence is in accordance with the priority level. This means that
// two normal DMA cannot be used to do simultaneous read and write. This
// feature is critical for bus bitbanging.
type dmaR8NormalGroup struct {
cfg ndmaR8Cfg // NDMA_CTRL_REG
srcAddr uint32 // NDMA_SRC_ADDR_REG
dstAddr uint32 // NDMA_DEST_ADDR_REG
byteCounter uint32 // NDMA_BC_REG
reserved [4]uint32 //
}
func (d *dmaR8NormalGroup) isAvailable() bool {
return d.cfg == 0 && d.srcAddr == 0 && d.dstAddr == 0 && d.byteCounter == 0
}
func (d *dmaR8NormalGroup) release() error {
d.srcAddr = 0
d.dstAddr = 0
d.byteCounter = 0
d.cfg = ndmaLoad
//drvDMA.dmaMemory.irqEn &^= ...
//drvDMA.dmaMemory.irqPendStas &^= ...
return nil
}
// dmaNormalGroup is the control registers for the second block of 8 DMA
// controllers.
//
// They support different DReq and can do non-linear streaming.
type dmaDedicatedGroup struct {
cfg ddmaR8Cfg // DDMA_CTRL_REG
srcAddr uint32 // DDMA_SRC_ADDR_REG
dstAddr uint32 // DDMA_DEST_ADDR_REG
byteCounter uint32 // DDMA_BC_REG (24 bits)
reserved0 [2]uint32 //
param ddmaR8Param // DDMA_PARA_REG (dedicated DMA only)
reserved1 uint32 //
}
func (d *dmaDedicatedGroup) isAvailable() bool {
return d.cfg == 0 && d.srcAddr == 0 && d.dstAddr == 0 && d.byteCounter == 0 && d.param == 0
}
func (d *dmaDedicatedGroup) set(srcAddr, dstAddr, l uint32, srcIO, dstIO bool, src ddmaR8Cfg) {
d.srcAddr = srcAddr
d.dstAddr = dstAddr
d.byteCounter = l
// TODO(maruel): Slow down the clock by another 2*250x
//d.param = ddmaR8Param(250 | 250<<16)
d.param = ddmaR8Param(1<<24 | 1<<8 | 1)
// All these have value 0. This statement only exist for documentation.
cfg := ddmaDstWidth8 | ddmaDstBurst1 | ddmaDstLinear | ddmaSrcWidth8 | ddmaSrcLinear | ddmaSrcBurst1
cfg |= src | ddmaBCRemain
if srcIO {
cfg |= ddmaSrcIOMode
} else if dstIO {
cfg |= ddmaDstIOMode
}
d.cfg = ddmaLoad | cfg
for i := 0; d.cfg&ddmaLoad != 0 && i < 100000; i++ {
}
if d.cfg&ddmaLoad != 0 {
log.Printf("failed to load DDMA: %# v\n", d)
}
}
func (d *dmaDedicatedGroup) release() error {
d.param = 0
d.srcAddr = 0
d.dstAddr = 0
d.byteCounter = 0
d.cfg = ddmaLoad
//drvDMA.dmaMemory.irqEn &^= ...
//drvDMA.dmaMemory.irqPendStas &^= ...
return nil
}
const (
// 31 reserved
dma7QueueEndIrq dmaA64Irq = 1 << 30 // DMA7_END_IRQ_EN; DMA 7 Queue End Transfer Interrupt Enable.
dma7PackageEndIrq dmaA64Irq = 1 << 29 // DMA7_PKG_IRQ_EN; DMA 7 Package End Transfer Interrupt Enable.
dma7HalfIrq dmaA64Irq = 1 << 28 // DMA7_HLAF_IRQ_EN; DMA 7 Half Package Transfer Interrupt Enable.
// ...
// 3 reserved
dma0QueueEndIrq dmaA64Irq = 1 << 2 // DMA0_END_IRQ_EN; DMA 0 Queue End Transfer Interrupt Enable.
dma0PackageEndIrq dmaA64Irq = 1 << 1 // DMA0_PKG_IRQ_EN; DMA 0 Package End Transfer Interrupt Enable.
dma0HalfIrq dmaA64Irq = 1 << 0 // DMA0_HLAF_IRQ_EN; DMA 0 Half Package Transfer Interrupt Enable.
)
// DMA_IRQ_EN_REG
// A64: Page 199-201.
type dmaA64Irq uint32
const (
ddma7EndIrq dmaR8Irq = 1 << 31 // DDMA7_END_IRQ_EN
ddma7HalfIreq dmaR8Irq = 1 << 30 // DDMA7_HF_IRQ_EN
// ...
ddma0EndIrq dmaR8Irq = 1 << 17 // DDMA0_END_IRQ_EN
ddma0HalfIreq dmaR8Irq = 1 << 16 // DDMA0_HF_IRQ_EN
ndma7EndIrq dmaR8Irq = 1 << 15 // NDMA7_END_IRQ_EN
ndma7HalfIreq dmaR8Irq = 1 << 16 // NDDMA7_HF_IRQ_EN
// ...
ndma0EndIrq dmaR8Irq = 1 << 1 // NDMA0_END_IRQ_EN
ndma0HFIreq dmaR8Irq = 1 << 0 // NDMA0_HF_IRQ_EN
)
// DMA_IRQ_EN_REG
// R8: Page 124-126.
type dmaR8Irq uint32
const (
// 31 reserved
dma7QueueEndIrqPend dmaA64PendingIrq = 1 << 30 // DMA7_QUEUE_IRQ_PEND; DMA 7 Queue End Transfer Interrupt Pending. Set 1 to the bit will clear it.
dma7PackageEndIrqPend dmaA64PendingIrq = 1 << 29 // DMA7_PKG_IRQ_PEND; DMA 7 Package End Transfer Interrupt Pending. Set 1 to the bit will clear it.
dma7HalfIrqPend dmaA64PendingIrq = 1 << 28 // DMA7_HLAF_IRQ_PEND; DMA 7 Half Package Transfer Interrupt Pending. Set 1 to the bit will clear it.
// ...
// 3 reserved
dma0QueueEndIrqPend dmaA64PendingIrq = 1 << 2 // DMA0_QUEUE_IRQ_PEND; DMA 0 Queue End Transfer Interrupt Pending. Set 1 to the bit will clear it.
dma0PackageEndIrqPend dmaA64PendingIrq = 1 << 1 // DMA0_PKG_IRQ_PEND; DMA 0 Package End Transfer Interrupt Pending. Set 1 to the bit will clear it.
dma0HalfIrqPend dmaA64PendingIrq = 1 << 0 // DMA0_HLAF_IRQ_PEND; DMA 0 Half Package Transfer Interrupt Pending. Set 1 to the bit will clear it.
)
// DMA_IRQ_PEND_REG0
// A64: Page 201-203.
type dmaA64PendingIrq uint32
const (
ddma7EndIrqPend dmaR8PendingIrq = 1 << 31 // DDMA7_END_IRQ_PEND
ddma7HalfIreqPend dmaR8PendingIrq = 1 << 30 // DDMA7_HF_IRQ_PEND
// ...
ddma0EndIrqPend dmaR8PendingIrq = 1 << 17 // DDMA0_END_IRQ_PEND
ddma0HalfIreqPend dmaR8PendingIrq = 1 << 16 // DDMA0_HF_IRQ_PEND
ndma7EndIrqPend dmaR8PendingIrq = 1 << 15 // NDMA7_END_IRQ_PEND
ndma7HalfIreqPend dmaR8PendingIrq = 1 << 16 // NDDMA7_HF_IRQ_PEND
// ...
ndma0EndIrqPend dmaR8PendingIrq = 1 << 1 // NDMA0_END_IRQ_PEND
ndma0HalfIreqPend dmaR8PendingIrq = 1 << 0 // NDMA0_HF_IRQ_PEND
)
// DMA_IRQ_PEND_STAS_REG
// R8: Page 126-129.
type dmaR8PendingIrq uint32
const (
ndmaLoad ndmaR8Cfg = 1 << 31 // NDMA_LOAD
ndmaContinuous ndmaR8Cfg = 1 << 30 // NDMA_CONTI_EN Continuous mode
ndmaWaitClk0 ndmaR8Cfg = 0 << 27 // NDMA_WAIT_STATE Number of clock to wait for
ndmaWaitClk2 ndmaR8Cfg = 1 << 27 // 2(n+1)
ndmaWaitClk6 ndmaR8Cfg = 2 << 27 //
ndmaWaitClk8 ndmaR8Cfg = 3 << 27 //
ndmaWaitClk10 ndmaR8Cfg = 4 << 27 //
ndmaWaitClk12 ndmaR8Cfg = 5 << 27 //
ndmaWaitClk14 ndmaR8Cfg = 6 << 27 //
ndmaWaitClk16 ndmaR8Cfg = 7 << 27 //
ndmaDstWidth32 ndmaR8Cfg = 2 << 25 // NDMA_DST_DATA_WIDTH
ndmaDstWidth16 ndmaR8Cfg = 1 << 25 //
ndmaDstWidth8 ndmaR8Cfg = 0 << 25 //
ndmaDstBurst8 ndmaR8Cfg = 2 << 23 // NDMA_DST_BST_LEN
ndmaDstBurst4 ndmaR8Cfg = 1 << 23 //
ndmaDstBurst1 ndmaR8Cfg = 0 << 23 //
// 22 reserved NDMA_CFG_DST_NON_SECURE ?
ndmaDstAddrNoInc ndmaR8Cfg = 1 << 21 // NDMA_DST_ADDR_TYPE
ndmaDstDrqIRTX ndmaR8Cfg = 0 << 16 // NDMA_DST_DRQ_TYPE
ndmaDstDrqUART1TX ndmaR8Cfg = 9 << 16 //
ndmaDstDrqUART3TX ndmaR8Cfg = 11 << 16 //
ndmaDstDrqAudio ndmaR8Cfg = 19 << 16 // 24.576MHz (Page 53)
ndmaDstDrqSRAM ndmaR8Cfg = 21 << 16 //
ndmaDstDrqSPI0TX ndmaR8Cfg = 24 << 16 //
ndmaDstDrqSPI1TX ndmaR8Cfg = 25 << 16 //
ndmaDstDrqSPI2TX ndmaR8Cfg = 26 << 16 //
ndmaDstDrqUSB1 ndmaR8Cfg = 27 << 16 // 480MHz
ndmaDstDrqUSB2 ndmaR8Cfg = 28 << 16 //
ndmaDstDrqUSB3 ndmaR8Cfg = 29 << 16 //
ndmaDstDrqUSB4 ndmaR8Cfg = 30 << 16 //
ndmaDstDrqUSB5 ndmaR8Cfg = 31 << 16 //
ndmaBCRemain ndmaR8Cfg = 1 << 15 // BC_MODE_SEL
// 14:11 reserved
ndmaSrcWidth32 ndmaR8Cfg = 2 << 9 // NDMA_SRC_DATA_WIDTH
ndmaSrcWidth16 ndmaR8Cfg = 1 << 9 //
ndmaSrcWidth8 ndmaR8Cfg = 0 << 9 //
ndmaSrcBurst8 ndmaR8Cfg = 2 << 7 // NDMA_SRC_BST_LEN
ndmaSrcBurst4 ndmaR8Cfg = 1 << 7 //
ndmaSrcBurst1 ndmaR8Cfg = 0 << 7 //
// 6 reserved NDMA_CFG_SRC_NON_SECURE ?
ndmaSrcAddrNoInc ndmaR8Cfg = 1 << 5 // NDMA_SRC_ADDR_TYPE
ndmaSrcDrqIRTX ndmaR8Cfg = 0 << 0 // NDMA_SRC_DRQ_TYPE
ndmaSrcDrqUART1RX ndmaR8Cfg = 9 << 0 //
ndmaSrcDrqUART3RX ndmaR8Cfg = 11 << 0 //
ndmaSrcDrqAudio ndmaR8Cfg = 19 << 0 // 24.576MHz (Page 53)
ndmaSrcDrqSRAM ndmaR8Cfg = 21 << 0 //
ndmaSrcDrqSDRAM ndmaR8Cfg = 22 << 0 // 0~400MHz
ndmaSrcDrqTPAD ndmaR8Cfg = 23 << 0 //
ndmaSrcDrqSPI0RX ndmaR8Cfg = 24 << 0 //
ndmaSrcDrqSPI1RX ndmaR8Cfg = 25 << 0 //
ndmaSrcDrqSPI2RX ndmaR8Cfg = 26 << 0 //
ndmaSrcDrqUSB1 ndmaR8Cfg = 27 << 0 // 480MHz
ndmaSrcDrqUSB2 ndmaR8Cfg = 28 << 0 //
ndmaSrcDrqUSB3 ndmaR8Cfg = 29 << 0 //
ndmaSrcDrqUSB4 ndmaR8Cfg = 30 << 0 //
ndmaSrcDrqUSB5 ndmaR8Cfg = 31 << 0 //
)
// NDMA_CTRL_REG
// R8: Page 129-131.
type ndmaR8Cfg uint32
const (
ddmaLoad ddmaR8Cfg = 1 << 31 // DDMA_LOAD
ddmaBusy ddmaR8Cfg = 1 << 30 // DDMA_BSY_STA
ddmaContinuous ddmaR8Cfg = 1 << 29 // DDMA_CONTI_MODE_EN
// 28:27 reserved 28 = DDMA_CFG_DST_NON_SECURE ?
ddmaDstWidth32 ddmaR8Cfg = 2 << 25 // DDMA_DST_DATA_WIDTH
ddmaDstWidth16 ddmaR8Cfg = 1 << 25 //
ddmaDstWidth8 ddmaR8Cfg = 0 << 25 //
ddmaDstBurst8 ddmaR8Cfg = 2 << 23 // DDMA_DST_BST_LEN
ddmaDstBurst4 ddmaR8Cfg = 1 << 23 //
ddmaDstBurst1 ddmaR8Cfg = 0 << 23 //
ddmaDstVertical ddmaR8Cfg = 3 << 21 // DDMA_ADDR_MODE; no idea what it's use it. It's not explained in the datasheet ...
ddmaDstHorizontal ddmaR8Cfg = 2 << 21 // ... and the official drivers/dma/sun6i-dma.c driver doesn't use it
ddmaDstIOMode ddmaR8Cfg = 1 << 21 // Non incrementing
ddmaDstLinear ddmaR8Cfg = 0 << 21 // Normal incrementing position
ddmaDstDrqSRAM ddmaR8Cfg = 0 << 16 // DDMA_DST_DRQ_SEL
ddmaDstDrqSDRAM ddmaR8Cfg = 1 << 16 // DDR ram speed
ddmaDstDrqNAND ddmaR8Cfg = 3 << 16 //
ddmaDstDrqUSB0 ddmaR8Cfg = 4 << 16 //
ddmaDstDrqSPI1TX ddmaR8Cfg = 8 << 16 //
ddmaDstDrqCryptoTX ddmaR8Cfg = 10 << 16 //
ddmaDstDrqTCON0 ddmaR8Cfg = 14 << 16 //
ddmaDstDrqSPI0TX ddmaR8Cfg = 26 << 16 //
ddmaDstDrqSPI2TX ddmaR8Cfg = 28 << 16 //
ddmaBCRemain ddmaR8Cfg = 1 << 15 // BC_MODE_SEL
// 14:11 reserved
ddmaSrcWidth32 ddmaR8Cfg = 2 << 9 // DDMA_SRC_DATA_WIDTH
ddmaSrcWidth16 ddmaR8Cfg = 1 << 9 //
ddmaSrcWidth8 ddmaR8Cfg = 0 << 9 //
ddmaSrcBurst8 ddmaR8Cfg = 2 << 7 // DDMA_SRC_BST_LEN
ddmaSrcBurst4 ddmaR8Cfg = 1 << 7 //
ddmaSrcBurst1 ddmaR8Cfg = 0 << 7 //
ddmaSrcVertical ddmaR8Cfg = 3 << 5 // DDMA_SRC_ADDR_MODE
ddmaSrcHorizontal ddmaR8Cfg = 2 << 5 //
ddmaSrcIOMode ddmaR8Cfg = 1 << 5 // Non incrementing
ddmaSrcLinear ddmaR8Cfg = 0 << 5 // Normal incrementing position
// 4:0 drq
ddmaSrcDrqSRAM ddmaR8Cfg = 0 << 0 // DDMA_SRC_DRQ_TYPE
ddmaSrcDrqSDRAM ddmaR8Cfg = 1 << 0 //
ddmaSrcDrqNAND ddmaR8Cfg = 3 << 0 //
ddmaSrcDrqUSB0 ddmaR8Cfg = 4 << 0 //
ddmaSrcDrqSPI1RX ddmaR8Cfg = 9 << 0 //
ddmaSrcDrqCryptoRX ddmaR8Cfg = 11 << 0 //
ddmaSrcDrqSPI0RX ddmaR8Cfg = 27 << 0 //
ddmaSrcDrqSPI2RX ddmaR8Cfg = 29 << 0 //
)
// DDMA_CFG_REG
// R8: Page 131-134.
type ddmaR8Cfg uint32
const (
// For each value, N+1 is actually used.
ddmaDstBlkSizeMask ddmaR8Param = 0xFF << 24 // DEST_DATA_BLK_SIZE
ddmaDstWaitClkCycleMask ddmaR8Param = 0xFF << 16 // DEST_WAIT_CLK_CYC
ddmaSrcBlkSizeMask ddmaR8Param = 0xFF << 8 // SRC_DATA_BLK_SIZE
ddmaSrcWaitClkCycleMask ddmaR8Param = 0xFF << 0 // SRC_WAIT_CLK_CYC
)
// DDMA_PARA_REG
// R8: Page 134.
type ddmaR8Param uint32
// smokeTest allocates two physical pages, ask the DMA controller to copy the
// data from one page to another (with a small offset) and make sure the
// content is as expected.
//
// This should take a fraction of a second and will make sure the driver is
// usable.
func smokeTest() error {
const size = 4096 // 4kb
const holeSize = 1 // Minimum DMA alignment.
alloc := func(s int) (pmem.Mem, error) {
return pmem.Alloc(s)
}
copyMem := func(pDst, pSrc uint64) error {
n := drvDMA.dmaMemory.getDedicated()
if n == -1 {
return errors.New("no channel available")
}
drvDMA.dmaMemory.irqEn &^= 3 << uint(2*n+16)
drvDMA.dmaMemory.irqPendStas = 3 << uint(2*n+16)
ch := &drvDMA.dmaMemory.dedicated[n]
defer func() {
_ = ch.release()
}()
ch.set(uint32(pSrc), uint32(pDst)+holeSize, 4096-2*holeSize, false, false, ddmaDstDrqSDRAM|ddmaSrcDrqSDRAM)
for ch.cfg&ddmaBusy != 0 {
}
return nil
}
return pmem.TestCopy(size, holeSize, alloc, copyMem)
}
// driverDMA implements periph.Driver.
//
// It implements much more than the DMA controller, it also exposes the clocks,
// the PWM and PCM controllers.
type driverDMA struct {
// dmaMemory is the memory map of the CPU DMA registers.
dmaMemory *dmaMap
// pwmMemory is the memory map of the CPU PWM registers.
pwmMemory *pwmMap
// spiMemory is the memory mapping for the spi CPU registers.
spiMemory *spiMap
// clockMemory is the memory mapping for the clock CPU registers.
clockMemory *clockMap
// timerMemory is the memory mapping for the timer CPU registers.
timerMemory *timerMap
}
func (d *driverDMA) String() string {
return "allwinner-dma"
}
func (d *driverDMA) Prerequisites() []string {
return []string{"allwinner-gpio"}
}
func (d *driverDMA) After() []string {
return nil
}
func (d *driverDMA) Init() (bool, error) {
// dmaBaseAddr is the physical base address of the DMA registers.
var dmaBaseAddr uint32
// pwmBaseAddr is the physical base address of the PWM registers.
var pwmBaseAddr uint32
// spiBaseAddr is the physical base address of the clock registers.
var spiBaseAddr uint32
// clockBaseAddr is the physical base address of the clock registers.
var clockBaseAddr uint32
// timerBaseAddr is the physical base address of the timer registers.
var timerBaseAddr uint32
if IsA64() {
// Page 198.
dmaBaseAddr = 0x1C02000
// Page 194.
pwmBaseAddr = 0x1C21400
// Page 161.
timerBaseAddr = 0x1C20C00
// Page 81.
clockBaseAddr = 0x1C20000
// Page Page 545.
spiBaseAddr = 0x01C68000
} else if IsR8() {
// Page 124.
dmaBaseAddr = 0x1C02000
// Page 83.
pwmBaseAddr = 0x1C20C00 + 0x200
// Page 85.
timerBaseAddr = 0x1C20C00
// Page 57.
clockBaseAddr = 0x1C20000
// Page 151.
spiBaseAddr = 0x01C05000
} else {
// H3
// Page 194.
//dmaBaseAddr = 0x1C02000
// Page 187.
//pwmBaseAddr = 0x1C21400
// Page 154.
//timerBaseAddr = 0x1C20C00
return false, errors.New("unsupported CPU architecture")
}
if err := pmem.MapAsPOD(uint64(dmaBaseAddr), &d.dmaMemory); err != nil {
if os.IsPermission(err) {
return true, fmt.Errorf("need more access, try as root: %v", err)
}
return true, err
}
if err := pmem.MapAsPOD(uint64(pwmBaseAddr), &d.pwmMemory); err != nil {
return true, err
}
if err := pmem.MapAsPOD(uint64(timerBaseAddr), &d.timerMemory); err != nil {
return true, err
}
if err := pmem.MapAsPOD(uint64(clockBaseAddr), &d.clockMemory); err != nil {
return true, err
}
if err := pmem.MapAsPOD(uint64(spiBaseAddr), &d.spiMemory); err != nil {
return true, err
}
return true, smokeTest()
}
func (d *driverDMA) Close() error {
// Stop DMA and PWM controllers.
return nil
}
func init() {
if false && isArm {
// TODO(maruel): This is intense, wait to be sure it works.
periph.MustRegister(&drvDMA)
}
}
var drvDMA driverDMA

33
vendor/periph.io/x/periph/host/allwinner/doc.go generated vendored Normal file
View File

@ -0,0 +1,33 @@
// 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 exposes the GPIO functionality that is common to all
// AllWinner processors.
//
// This driver implements memory-mapped GPIO pin manipulation and leverages
// sysfs-gpio for edge detection.
//
// If you are looking at the actual implementation, open doc.go for further
// implementation details.
//
// Datasheets
//
// A64: http://files.pine64.org/doc/datasheet/pine64/Allwinner_A64_User_Manual_V1.0.pdf
//
// H3: http://dl.linux-sunxi.org/H3/Allwinner_H3_Datasheet_V1.0.pdf
//
// R8: https://github.com/NextThingCo/CHIP-Hardware/raw/master/CHIP%5Bv1_0%5D/CHIPv1_0-BOM-Datasheets/Allwinner%20R8%20User%20Manual%20V1.1.pdf
//
// Physical overview: http://files.pine64.org/doc/datasheet/pine64/A64_Datasheet_V1.1.pdf
package allwinner
// Other implementation details
//
// The most active kernel branch is
// https://github.com/linux-sunxi/linux-sunxi/commits/sunxi-next
//
// In particular look at
// https://github.com/linux-sunxi/linux-sunxi/blob/sunxi-next/drivers/dma/sun4i-dma.c
// and
// https://github.com/linux-sunxi/linux-sunxi/blob/sunxi-next/drivers/dma/sun6i-dma.c

1065
vendor/periph.io/x/periph/host/allwinner/gpio.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

563
vendor/periph.io/x/periph/host/allwinner/gpio_pl.go generated vendored Normal file
View File

@ -0,0 +1,563 @@
// 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"
"os"
"path"
"strconv"
"strings"
"time"
"periph.io/x/periph"
"periph.io/x/periph/conn/gpio"
"periph.io/x/periph/conn/gpio/gpioreg"
"periph.io/x/periph/conn/physic"
"periph.io/x/periph/conn/pin"
"periph.io/x/periph/host/pmem"
"periph.io/x/periph/host/sysfs"
)
// All the pins in the PL group.
var PL0, PL1, PL2, PL3, PL4, PL5, PL6, PL7, PL8, PL9, PL10, PL11, PL12 *PinPL
// PinPL defines one CPU supported pin in the PL group.
//
// PinPL implements gpio.PinIO.
type PinPL struct {
// Immutable.
offset uint8 // as per register offset calculation
name string // name as per datasheet
defaultPull gpio.Pull // default pull at startup
// Immutable after driver initialization.
sysfsPin *sysfs.Pin // Set to the corresponding sysfs.Pin, if any.
available bool // Set when the pin is available on this CPU architecture.
// Mutable.
usingEdge bool // Set when edge detection is enabled.
}
// String implements conn.Resource.
//
// It returns the pin name and number, ex: "PL5(352)".
func (p *PinPL) String() string {
return fmt.Sprintf("%s(%d)", p.name, p.Number())
}
// Halt implements conn.Resource.
//
// It stops edge detection if enabled.
func (p *PinPL) Halt() error {
if p.usingEdge {
if err := p.sysfsPin.Halt(); err != nil {
return p.wrap(err)
}
p.usingEdge = false
}
return nil
}
// Name implements pin.Pin.
//
// It returns the pin name, ex: "PL5".
func (p *PinPL) Name() string {
return p.name
}
// Number implements pin.Pin.
//
// It returns the GPIO pin number as represented by gpio sysfs.
func (p *PinPL) Number() int {
return 11*32 + int(p.offset)
}
// Function implements pin.Pin.
func (p *PinPL) Function() string {
return string(p.Func())
}
// Func implements pin.PinFunc.
func (p *PinPL) Func() pin.Func {
if !p.available {
// We do not want the error message about uninitialized system.
return pin.FuncNone
}
if drvGPIOPL.gpioMemoryPL == nil {
if p.sysfsPin == nil {
return pin.FuncNone
}
return p.sysfsPin.Func()
}
switch f := p.function(); f {
case in:
if p.FastRead() {
return gpio.IN_HIGH
}
return gpio.IN_LOW
case out:
if p.FastRead() {
return gpio.OUT_HIGH
}
return gpio.OUT_LOW
case alt1:
if s := mappingPL[p.offset][0]; len(s) != 0 {
return pin.Func(s)
}
return pin.Func("ALT1")
case alt2:
if s := mappingPL[p.offset][1]; len(s) != 0 {
return pin.Func(s)
}
return pin.Func("ALT2")
case alt3:
if s := mappingPL[p.offset][2]; len(s) != 0 {
return pin.Func(s)
}
return pin.Func("ALT3")
case alt4:
if s := mappingPL[p.offset][3]; len(s) != 0 {
return pin.Func(s)
}
return pin.Func("ALT4")
case alt5:
if s := mappingPL[p.offset][4]; len(s) != 0 {
if strings.Contains(string(s), "_EINT") {
// It's an input supporting interrupts.
if p.FastRead() {
return gpio.IN_HIGH
}
return gpio.IN_LOW
}
return pin.Func(s)
}
return pin.Func("ALT5")
case disabled:
return pin.FuncNone
default:
return pin.FuncNone
}
}
// SupportedFuncs implements pin.PinFunc.
func (p *PinPL) SupportedFuncs() []pin.Func {
f := make([]pin.Func, 0, 2+2)
f = append(f, gpio.IN, gpio.OUT)
for _, m := range mappingPL[p.offset] {
if m != pin.FuncNone && !strings.Contains(string(m), "_EINT") {
f = append(f, m)
}
}
return f
}
// SetFunc implements pin.PinFunc.
func (p *PinPL) SetFunc(f pin.Func) error {
switch f {
case gpio.FLOAT:
return p.In(gpio.Float, gpio.NoEdge)
case gpio.IN:
return p.In(gpio.PullNoChange, gpio.NoEdge)
case gpio.IN_LOW:
return p.In(gpio.PullDown, gpio.NoEdge)
case gpio.IN_HIGH:
return p.In(gpio.PullUp, gpio.NoEdge)
case gpio.OUT_HIGH:
return p.Out(gpio.High)
case gpio.OUT_LOW:
return p.Out(gpio.Low)
default:
isGeneral := f == f.Generalize()
for i, m := range mappingPL[p.offset] {
if m == f || (isGeneral && m.Generalize() == f) {
if err := p.Halt(); err != nil {
return err
}
switch i {
case 0:
p.setFunction(alt1)
case 1:
p.setFunction(alt2)
case 2:
p.setFunction(alt3)
case 3:
p.setFunction(alt4)
case 4:
p.setFunction(alt5)
}
return nil
}
}
return p.wrap(errors.New("unsupported function"))
}
}
// In implements gpio.PinIn.
func (p *PinPL) In(pull gpio.Pull, edge gpio.Edge) error {
if !p.available {
// We do not want the error message about uninitialized system.
return p.wrap(errors.New("not available on this CPU architecture"))
}
if p.usingEdge && edge == gpio.NoEdge {
if err := p.sysfsPin.Halt(); err != nil {
return p.wrap(err)
}
p.usingEdge = false
}
if drvGPIOPL.gpioMemoryPL == nil {
if p.sysfsPin == nil {
return p.wrap(errors.New("subsystem gpiomem not initialized and sysfs not accessible; try running as root?"))
}
if pull != gpio.PullNoChange {
return p.wrap(errors.New("pull cannot be used when subsystem gpiomem not initialized; try running as root?"))
}
if err := p.sysfsPin.In(pull, edge); err != nil {
return p.wrap(err)
}
p.usingEdge = edge != gpio.NoEdge
return nil
}
if !p.setFunction(in) {
return p.wrap(errors.New("failed to set pin as input"))
}
if pull != gpio.PullNoChange {
off := p.offset / 16
shift := 2 * (p.offset % 16)
// Do it in a way that is concurrent safe.
drvGPIOPL.gpioMemoryPL.pull[off] &^= 3 << shift
switch pull {
case gpio.PullDown:
drvGPIOPL.gpioMemoryPL.pull[off] = 2 << shift
case gpio.PullUp:
drvGPIOPL.gpioMemoryPL.pull[off] = 1 << shift
default:
}
}
if edge != gpio.NoEdge {
if p.sysfsPin == nil {
return p.wrap(fmt.Errorf("pin %d is not exported by sysfs", p.Number()))
}
// This resets pending edges.
if err := p.sysfsPin.In(gpio.PullNoChange, edge); err != nil {
return p.wrap(err)
}
p.usingEdge = true
}
return nil
}
// Read implements gpio.PinIn.
func (p *PinPL) Read() gpio.Level {
if drvGPIOPL.gpioMemoryPL == nil {
if p.sysfsPin == nil {
return gpio.Low
}
return p.sysfsPin.Read()
}
return gpio.Level(drvGPIOPL.gpioMemoryPL.data&(1<<p.offset) != 0)
}
// FastRead reads without verification.
func (p *PinPL) FastRead() gpio.Level {
return gpio.Level(drvGPIOPL.gpioMemoryPL.data&(1<<p.offset) != 0)
}
// WaitForEdge implements gpio.PinIn.
func (p *PinPL) WaitForEdge(timeout time.Duration) bool {
if p.sysfsPin != nil {
return p.sysfsPin.WaitForEdge(timeout)
}
return false
}
// Pull implements gpio.PinIn.
func (p *PinPL) Pull() gpio.Pull {
if drvGPIOPL.gpioMemoryPL == nil {
// If gpioMemoryPL is set, p.available is true.
return gpio.PullNoChange
}
switch (drvGPIOPL.gpioMemoryPL.pull[p.offset/16] >> (2 * (p.offset % 16))) & 3 {
case 0:
return gpio.Float
case 1:
return gpio.PullUp
case 2:
return gpio.PullDown
default:
// Confused.
return gpio.PullNoChange
}
}
// DefaultPull implements gpio.PinIn.
func (p *PinPL) DefaultPull() gpio.Pull {
return p.defaultPull
}
// Out implements gpio.PinOut.
func (p *PinPL) Out(l gpio.Level) error {
if !p.available {
// We do not want the error message about uninitialized system.
return p.wrap(errors.New("not available on this CPU architecture"))
}
if drvGPIOPL.gpioMemoryPL == nil {
if p.sysfsPin != nil {
return p.wrap(errors.New("subsystem gpiomem not initialized and sysfs not accessible; try running as root?"))
}
return p.sysfsPin.Out(l)
}
// First disable edges.
if err := p.Halt(); err != nil {
return err
}
p.FastOut(l)
if !p.setFunction(out) {
return p.wrap(errors.New("failed to set pin as output"))
}
return nil
}
// FastOut sets a pin output level with Absolutely No error checking.
//
// See Pin.FastOut for more information.
func (p *PinPL) FastOut(l gpio.Level) {
bit := uint32(1 << p.offset)
if l {
drvGPIOPL.gpioMemoryPL.data |= bit
} else {
drvGPIOPL.gpioMemoryPL.data &^= bit
}
}
// PWM implements gpio.PinOut.
func (p *PinPL) PWM(gpio.Duty, physic.Frequency) error {
// TODO(maruel): PWM support for PL10.
return p.wrap(errors.New("not available on this CPU architecture"))
}
//
// function returns the current GPIO pin function.
//
// It must not be called if drvGPIOPL.gpioMemoryPL is nil.
func (p *PinPL) function() function {
shift := 4 * (p.offset % 8)
return function((drvGPIOPL.gpioMemoryPL.cfg[p.offset/8] >> shift) & 7)
}
// setFunction changes the GPIO pin function.
//
// Returns false if the pin was in AltN. Only accepts in and out
//
// It must not be called if drvGPIOPL.gpioMemoryPL is nil.
func (p *PinPL) setFunction(f function) bool {
if f != in && f != out {
return false
}
// Interrupt based edge triggering is Alt5 but this is only supported on some
// pins.
// TODO(maruel): This check should use a whitelist of pins.
if actual := p.function(); actual != in && actual != out && actual != disabled && actual != alt5 {
// Pin is in special mode.
return false
}
off := p.offset / 8
shift := 4 * (p.offset % 8)
mask := uint32(disabled) << shift
v := (uint32(f) << shift) ^ mask
// First disable, then setup. This is concurrent safe.
drvGPIOPL.gpioMemoryPL.cfg[off] |= mask
drvGPIOPL.gpioMemoryPL.cfg[off] &^= v
if p.function() != f {
panic(f)
}
return true
}
func (p *PinPL) wrap(err error) error {
return fmt.Errorf("allwinner-gpio-pl (%s): %v", p, err)
}
//
// cpuPinsPL is all the pins as supported by the CPU. There is no guarantee that
// they are actually connected to anything on the board.
var cpuPinsPL = []PinPL{
{offset: 0, name: "PL0", defaultPull: gpio.PullUp},
{offset: 1, name: "PL1", defaultPull: gpio.PullUp},
{offset: 2, name: "PL2", defaultPull: gpio.Float},
{offset: 3, name: "PL3", defaultPull: gpio.Float},
{offset: 4, name: "PL4", defaultPull: gpio.Float},
{offset: 5, name: "PL5", defaultPull: gpio.Float},
{offset: 6, name: "PL6", defaultPull: gpio.Float},
{offset: 7, name: "PL7", defaultPull: gpio.Float},
{offset: 8, name: "PL8", defaultPull: gpio.Float},
{offset: 9, name: "PL9", defaultPull: gpio.Float},
{offset: 10, name: "PL10", defaultPull: gpio.Float},
{offset: 11, name: "PL11", defaultPull: gpio.Float},
{offset: 12, name: "PL12", defaultPull: gpio.Float},
}
// See gpio.go for details.
var mappingPL = [13][5]pin.Func{
{"RSB_SCK", "I2C_SCL", "", "", "PL_EINT0"}, // PL0
{"RSB_SDA", "I2C_SDA", "", "", "PL_EINT1"}, // PL1
{"UART_TX", "", "", "", "PL_EINT2"}, // PL2
{"UART_RX", "", "", "", "PL_EINT3"}, // PL3
{"JTAG_TMS", "", "", "", "PL_EINT4"}, // PL4
{"JTAG_TCK", "", "", "", "PL_EINT5"}, // PL5
{"JTAG_TDO", "", "", "", "PL_EINT6"}, // PL6
{"JTAG_TDI", "", "", "", "PL_EINT7"}, // PL7
{"I2C_SCL", "", "", "", "PL_EINT8"}, // PL8
{"I2C_SDA", "", "", "", "PL_EINT9"}, // PL9
{"PWM0", "", "", "", "PL_EINT10"}, // PL10
{"CIR_RX", "", "", "", "PL_EINT11"}, // PL11
{"", "", "", "", "PL_EINT12"}, // PL12
}
func init() {
PL0 = &cpuPinsPL[0]
PL1 = &cpuPinsPL[1]
PL2 = &cpuPinsPL[2]
PL3 = &cpuPinsPL[3]
PL4 = &cpuPinsPL[4]
PL5 = &cpuPinsPL[5]
PL6 = &cpuPinsPL[6]
PL7 = &cpuPinsPL[7]
PL8 = &cpuPinsPL[8]
PL9 = &cpuPinsPL[9]
PL10 = &cpuPinsPL[10]
PL11 = &cpuPinsPL[11]
PL12 = &cpuPinsPL[12]
}
// getBaseAddressPL queries the virtual file system to retrieve the base address
// of the GPIO registers for GPIO pins in group PL.
//
// Defaults to 0x01F02C00 as per datasheet if could query the file system.
func getBaseAddressPL() uint64 {
base := uint64(0x01F02C00)
link, err := os.Readlink("/sys/bus/platform/drivers/sun50i-r-pinctrl/driver")
if err != nil {
return base
}
parts := strings.SplitN(path.Base(link), ".", 2)
if len(parts) != 2 {
return base
}
base2, err := strconv.ParseUint(parts[0], 16, 64)
if err != nil {
return base
}
return base2
}
// driverGPIOPL implements periph.Driver.
type driverGPIOPL struct {
// gpioMemoryPL is only the PL group in that case. Note that groups PI, PJ, PK
// do not exist.
gpioMemoryPL *gpioGroup
}
func (d *driverGPIOPL) String() string {
return "allwinner-gpio-pl"
}
func (d *driverGPIOPL) Prerequisites() []string {
return nil
}
func (d *driverGPIOPL) After() []string {
return []string{"sysfs-gpio"}
}
func (d *driverGPIOPL) Init() (bool, error) {
// BUG(maruel): H3 supports group PL too.
if !IsA64() {
return false, errors.New("A64 CPU not detected")
}
// Mark the right pins as available even if the memory map fails so they can
// callback to sysfs.Pins.
functions := map[pin.Func]struct{}{}
for i := range cpuPinsPL {
name := cpuPinsPL[i].Name()
num := strconv.Itoa(cpuPinsPL[i].Number())
cpuPinsPL[i].available = true
gpion := "GPIO" + num
// Unregister the pin if already registered. This happens with sysfs-gpio.
// Do not error on it, since sysfs-gpio may have failed to load.
_ = gpioreg.Unregister(gpion)
_ = gpioreg.Unregister(num)
// Register the pin with gpio.
if err := gpioreg.Register(&cpuPinsPL[i]); err != nil {
return true, err
}
if err := gpioreg.RegisterAlias(gpion, name); err != nil {
return true, err
}
if err := gpioreg.RegisterAlias(num, name); err != nil {
return true, err
}
switch f := cpuPinsPL[i].Func(); f {
case gpio.IN, gpio.OUT, pin.FuncNone:
default:
// Registering the same alias twice fails. This can happen if two pins
// are configured with the same function.
if _, ok := functions[f]; !ok {
// TODO(maruel): We'd have to clear out the ones from allwinner-gpio
// too.
functions[f] = struct{}{}
_ = gpioreg.RegisterAlias(string(f), name)
}
}
}
// Now do a second loop but do the alternate functions.
for i := range cpuPinsPL {
for _, f := range cpuPinsPL[i].SupportedFuncs() {
switch f {
case gpio.IN, gpio.OUT:
default:
if _, ok := functions[f]; !ok {
// TODO(maruel): We'd have to clear out the ones from allwinner-gpio
// too.
functions[f] = struct{}{}
_ = gpioreg.RegisterAlias(string(f), cpuPinsPL[i].name)
}
}
}
}
m, err := pmem.Map(getBaseAddressPL(), 4096)
if err != nil {
if os.IsPermission(err) {
return true, fmt.Errorf("need more access, try as root: %v", err)
}
return true, err
}
if err := m.AsPOD(&d.gpioMemoryPL); err != nil {
return true, err
}
return true, nil
}
func init() {
if isArm {
periph.MustRegister(&drvGPIOPL)
}
}
var drvGPIOPL driverGPIOPL
var _ gpio.PinIO = &PinPL{}
var _ gpio.PinIn = &PinPL{}
var _ gpio.PinOut = &PinPL{}
var _ pin.PinFunc = &PinPL{}

197
vendor/periph.io/x/periph/host/allwinner/pwm.go generated vendored Normal file
View File

@ -0,0 +1,197 @@
// 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 (
"fmt"
"strings"
"time"
)
const pwmClock = 24000000
const pwmMaxPeriod = 0x10000
// prescalers is the value for pwm0Prescale*
var prescalers = []struct {
freq uint32
scaler pwmPrescale
}{
// Base frequency (min freq is half that) / PWM clock at pwmMaxPeriod
{pwmClock, pwmPrescale1}, // 24MHz / 366Hz
{pwmClock / 120, pwmPrescale120}, // 200kHz / 3Hz
{pwmClock / 180, pwmPrescale180}, // 133kHz / 2Hz
{pwmClock / 240, pwmPrescale240}, // 100kHz / 1.5Hz
{pwmClock / 360, pwmPrescale360}, // 66kHz / 1.01Hz
{pwmClock / 480, pwmPrescale480}, // 50kHz / 0.7Hz
{pwmClock / 12000, pwmPrescale12000}, // 2kHz
{pwmClock / 24000, pwmPrescale24000}, // 1kHz
{pwmClock / 36000, pwmPrescale36000}, // 666 Hz
{pwmClock / 48000, pwmPrescale48000}, // 500 Hz
{pwmClock / 72000, pwmPrescale72000}, // 333 Hz / 0.005Hz
}
const (
// 31:29 reserved
pwmBusy pwmCtl = 1 << 28 // PWM0_RDY
// 27:10 reserved (used for pwm1)
pwm0Mask pwmCtl = (1 << 10) - 1
pwm0Bypass pwmCtl = 1 << 9 // PWM0_BYPASS (marked as unused on some drivers?)
pwm0PulseStart pwmCtl = 1 << 8 // PWM_CH0_PUL_START
pwm0ModePulse pwmCtl = 1 << 7 // PWM_CHANNEL0_MODE
pwm0SCLK pwmCtl = 1 << 6 // SCLK_CH0_GATING
pwm0Polarity pwmCtl = 1 << 5 // PWM_CH0_ACT_STA
pwm0Enable pwmCtl = 1 << 4 // PWM_CH0_EN
// 3:0
pwm0PrescaleMask pwmCtl = pwmCtl(pwmPrescaleMask) // PWM_CH0_PRESCAL
pwm0Prescale120 pwmCtl = pwmCtl(pwmPrescale120)
pwm0Prescale180 pwmCtl = pwmCtl(pwmPrescale180)
pwm0Prescale240 pwmCtl = pwmCtl(pwmPrescale240)
pwm0Prescale360 pwmCtl = pwmCtl(pwmPrescale360)
pwm0Prescale480 pwmCtl = pwmCtl(pwmPrescale480)
// 5, 6, 7 reserved
pwm0Prescale12000 pwmCtl = pwmCtl(pwmPrescale12000)
pwm0Prescale24000 pwmCtl = pwmCtl(pwmPrescale24000)
pwm0Prescale36000 pwmCtl = pwmCtl(pwmPrescale36000)
pwm0Prescale48000 pwmCtl = pwmCtl(pwmPrescale48000)
pwm0Prescale72000 pwmCtl = pwmCtl(pwmPrescale72000)
// 13, 14 reserved
pwm0Prescale1 pwmCtl = pwmCtl(pwmPrescale1)
)
// A64: Pages 194-195.
// R8: Pages 83-84.
type pwmCtl uint32
func (p pwmCtl) String() string {
var out []string
if p&pwmBusy != 0 {
out = append(out, "PWM0_RDY")
p &^= pwmBusy
}
if p&pwm0Bypass != 0 {
out = append(out, "PWM0_BYPASS")
p &^= pwm0Bypass
}
if p&pwm0PulseStart != 0 {
out = append(out, "PWM0_CH0_PUL_START")
p &^= pwm0PulseStart
}
if p&pwm0ModePulse != 0 {
out = append(out, "PWM0_CHANNEL0_MODE")
p &^= pwm0ModePulse
}
if p&pwm0SCLK != 0 {
out = append(out, "SCLK_CH0_GATING")
p &^= pwm0SCLK
}
if p&pwm0Polarity != 0 {
out = append(out, "PWM_CH0_ACT_STA")
p &^= pwm0Polarity
}
if p&pwm0Enable != 0 {
out = append(out, "PWM_CH0_EN")
p &^= pwm0Enable
}
out = append(out, pwmPrescale(p&pwm0PrescaleMask).String())
p &^= pwm0PrescaleMask
if p != 0 {
out = append(out, fmt.Sprintf("Unknown(0x%08X)", uint32(p)))
}
return strings.Join(out, "|")
}
const (
pwmPrescaleMask pwmPrescale = 0xF
pwmPrescale120 pwmPrescale = 0
pwmPrescale180 pwmPrescale = 1
pwmPrescale240 pwmPrescale = 2
pwmPrescale360 pwmPrescale = 3
pwmPrescale480 pwmPrescale = 4
// 5, 6, 7 reserved
pwmPrescale12000 pwmPrescale = 8
pwmPrescale24000 pwmPrescale = 9
pwmPrescale36000 pwmPrescale = 10
pwmPrescale48000 pwmPrescale = 11
pwmPrescale72000 pwmPrescale = 12
// 13, 14 reserved
pwmPrescale1 pwmPrescale = 15
)
type pwmPrescale uint32
func (p pwmPrescale) String() string {
switch p {
case pwmPrescale120:
return "/120"
case pwmPrescale180:
return "/180"
case pwmPrescale240:
return "/240"
case pwmPrescale360:
return "/360"
case pwmPrescale480:
return "/480"
case pwmPrescale12000:
return "/12k"
case pwmPrescale24000:
return "/24k"
case pwmPrescale36000:
return "/36k"
case pwmPrescale48000:
return "/48k"
case pwmPrescale72000:
return "/72k"
case pwmPrescale1:
return "/1"
default:
return fmt.Sprintf("InvalidScalar(%d)", p&pwmPrescaleMask)
}
}
// A64: Page 195.
// R8: Page 84
type pwmPeriod uint32
func (p pwmPeriod) String() string {
return fmt.Sprintf("%d/%d", p&0xFFFF, uint32((p>>16)&0xFFFF)+1)
}
func toPeriod(total uint32, active uint16) pwmPeriod {
if total > pwmMaxPeriod {
total = pwmMaxPeriod
}
return pwmPeriod(total-1)<<16 | pwmPeriod(active)
}
// getBestPrescale finds the best prescaler.
//
// Cycles must be between 2 and 0x10000/2.
func getBestPrescale(period time.Duration) pwmPrescale {
// TODO(maruel): Rewrite this function, it is incorrect.
for _, v := range prescalers {
p := time.Second / time.Duration(v.freq)
smallest := (period / pwmMaxPeriod)
largest := (period / 2)
if p > smallest && p < largest {
return v.scaler
}
}
// Period is longer than 196s.
return pwmPrescale72000
}
// pwmMap represents the PWM memory mapped CPU registers.
//
// The base frequency is 24Mhz.
//
// TODO(maruel): Some CPU have 2 PWMs.
type pwmMap struct {
ctl pwmCtl // PWM_CTRL_REG
period pwmPeriod // PWM_CH0_PERIOD
}
func (p *pwmMap) String() string {
return fmt.Sprintf("pwmMap{%s, %v}", p.ctl, p.period)
}

149
vendor/periph.io/x/periph/host/allwinner/r8.go generated vendored Normal file
View File

@ -0,0 +1,149 @@
// 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.
// This file contains pin mapping information that is specific to the Allwinner
// R8 model.
package allwinner
import (
"strings"
"periph.io/x/periph/conn/pin"
"periph.io/x/periph/host/sysfs"
)
// R8 specific pins.
var (
FEL *pin.BasicPin // Boot mode selection
MIC_IN *pin.BasicPin // Microphone in
MIC_GND *pin.BasicPin // Microphone ground
HP_LEFT *pin.BasicPin // Left speaker out
HP_RIGHT *pin.BasicPin // Right speaker out
HP_COM *pin.BasicPin // Speaker common
X1, X2, Y1, Y2 *pin.BasicPin // Touch screen pins
)
//
func init() {
FEL = &pin.BasicPin{N: "FEL"}
MIC_IN = &pin.BasicPin{N: "MIC_IN"}
MIC_GND = &pin.BasicPin{N: "MIC_GND"}
HP_LEFT = &pin.BasicPin{N: "HP_LEFT"}
HP_RIGHT = &pin.BasicPin{N: "HP_RIGHT"}
HP_COM = &pin.BasicPin{N: "HP_COM"}
X1 = &pin.BasicPin{N: "X1"}
X2 = &pin.BasicPin{N: "X2"}
Y1 = &pin.BasicPin{N: "Y1"}
Y2 = &pin.BasicPin{N: "Y2"}
}
// mappingR8 describes the mapping of each R8 processor gpio to their alternate
// functions.
//
// It omits the in & out functions which are available on all pins.
//
// The mapping comes from the datasheet page 18:
// https://github.com/NextThingCo/CHIP-Hardware/raw/master/CHIP%5Bv1_0%5D/CHIPv1_0-BOM-Datasheets/Allwinner%20R8%20Datasheet%20V1.2.pdf
//
// - The datasheet uses TWI instead of I2C but this is renamed here for consistency.
var mappingR8 = map[string][5]pin.Func{
"PB0": {"I2C0_SCL"},
"PB1": {"I2C0_SDA"},
"PB2": {"PWM0", "", "", "", "EINT16"},
"PB3": {"IR_TX", "", "", "", "EINT17"},
"PB4": {"IR_RX", "", "", "", "EINT18"},
"PB10": {"SPI2_CS1"},
"PB15": {"I2C1_SCL"},
"PB16": {"I2C1_SDA"},
"PB17": {"I2C2_SCL"},
"PB18": {"I2C2_SDA"},
"PC0": {"NAND_WE", "SPI0_MOSI"},
"PC1": {"NAND_ALE", "SPI0_MISO"},
"PC2": {"NAND_CLE", "SPI0_CLK"},
"PC3": {"NAND_CE1", "SPI0_CS0"},
"PC4": {"NAND_CE0"},
"PC5": {"NAND_RE"},
"PC6": {"NAND_RB0", "SDC2_CMD"},
"PC7": {"NAND_RB1", "SDC2_CLK"},
"PC8": {"NAND_DQ0", "SDC2_D0"},
"PC9": {"NAND_DQ1", "SDC2_D1"},
"PC10": {"NAND_DQ2", "SDC2_D2"},
"PC11": {"NAND_DQ3", "SDC2_D3"},
"PC12": {"NAND_DQ4", "SDC2_D4"},
"PC13": {"NAND_DQ5", "SDC2_D5"},
"PC14": {"NAND_DQ6", "SDC2_D6"},
"PC15": {"NAND_DQ7", "SDC2_D7"},
"PC19": {""},
"PD2": {"LCD_D2", "UART2_TX"},
"PD3": {"LCD_D3", "UART2_RX"},
"PD4": {"LCD_D4", "UART2_CTX"},
"PD5": {"LCD_D5", "UART2_RTS"},
"PD6": {"LCD_D6", "ECRS"},
"PD7": {"LCD_D7", "ECOL"},
"PD10": {"LCD_D10", "ERXD0"},
"PD11": {"LCD_D11", "ERXD1"},
"PD12": {"LCD_D12", "ERXD2"},
"PD13": {"LCD_D13", "ERXD3"},
"PD14": {"LCD_D14", "ERXCK"},
"PD15": {"LCD_D15", "ERXERR"},
"PD18": {"LCD_D18", "ERXDV"},
"PD19": {"LCD_D19", "ETXD0"},
"PD20": {"LCD_D20", "ETXD1"},
"PD21": {"LCD_D21", "ETXD2"},
"PD22": {"LCD_D22", "ETXD3"},
"PD23": {"LCD_D23", "ETXEN"},
"PD24": {"LCD_CLK", "ETXCK"},
"PD25": {"LCD_DE", "ETXERR"},
"PD26": {"LCD_HSYNC", "EMDC"},
"PD27": {"LCD_VSYNC", "EMDIO"},
"PE0": {"TS_CLK", "CSI_PCLK", "SPI2_CS0", "", "EINT14"},
"PE1": {"TS_ERR", "CSI_MCLK", "SPI2_CLK", "", "EINT15"},
"PE2": {"TS_SYNC", "CSI_HSYNC", "SPI2_MOSI"},
"PE3": {"TS_DVLD", "CSI_VSYNC", "SPI2_MISO"},
"PE4": {"TS_D0", "CSI_D0", "SDC2_D0"},
"PE5": {"TS_D1", "CSI_D1", "SDC2_D1"},
"PE6": {"TS_D2", "CSI_D2", "SDC2_D2"},
"PE7": {"TS_D3", "CSI_D3", "SDC2_D3"},
"PE8": {"TS_D4", "CSI_D4", "SDC2_CMD"},
"PE9": {"TS_D5", "CSI_D5", "SDC2_CLK"},
"PE10": {"TS_D6", "CSI_D6", "UART1_TX"},
"PE11": {"TS_D7", "CSI_D7", "UART1_RX"},
"PF0": {"SDC0_D1", "", "JTAG1_TMS"},
"PF1": {"SDC0_D0", "", "JTAG1_TDI"},
"PF2": {"SDC0_CLK", "", "UART0_TX"},
"PF3": {"SDC0_CMD", "", "JTAG1_TDO"},
"PF4": {"SDC0_D3", "", "UART0_RX"},
"PF5": {"SDC0_D2", "", "JTAG1_TCK"},
"PG0": {"GPS_CLK", "", "", "", "EINT0"},
"PG1": {"GPS_SIGN", "", "", "", "EINT1"},
"PG2": {"GPS_MAG", "", "", "", "EINT2"},
"PG3": {"", "", "UART1_TX", "", "EINT3"},
"PG4": {"", "", "UART1_RX", "", "EINT4"},
"PG9": {"SPI1_CS0", "UART3_TX", "", "", "EINT9"},
"PG10": {"SPI1_CLK", "UART3_RX", "", "", "EINT10"},
"PG11": {"SPI1_MOSI", "UART3_CTS", "", "", "EINT11"},
"PG12": {"SPI1_MISO", "UART3_RTS", "", "", "EINT12"},
}
// mapR8Pins uses mappingR8 to actually set the altFunc fields of all gpio and
// mark them as available.
//
// It is called by the generic allwinner processor code if a R8 is detected.
func mapR8Pins() error {
for name, altFuncs := range mappingR8 {
pin := cpupins[name]
pin.altFunc = altFuncs
pin.available = true
if strings.Contains(string(altFuncs[4]), "EINT") {
pin.supportEdge = true
}
// Initializes the sysfs corresponding pin right away.
pin.sysfsPin = sysfs.Pins[pin.Number()]
}
return nil
}

207
vendor/periph.io/x/periph/host/allwinner/spi.go generated vendored Normal file
View File

@ -0,0 +1,207 @@
// 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
}

128
vendor/periph.io/x/periph/host/allwinner/timer.go generated vendored Normal file
View File

@ -0,0 +1,128 @@
// 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 (
"time"
"periph.io/x/periph/host/cpu"
)
// ReadTime returns the time on a monotonic timer.
//
// It only works if allwinner-dma successfully loaded. Otherwise it returns 0.
func ReadTime() time.Duration {
if drvDMA.timerMemory == nil {
return 0
}
v := uint64(drvDMA.timerMemory.counterHigh)<<32 | uint64(drvDMA.timerMemory.counterLow)
if v == 0 {
// BUG(maruel): Implement using AVS_CNT0_REG on A64.
return 0
}
// BUG(maruel): Assumes that counterCtrl & timerPLL6 is not set.
const tick = time.Microsecond / 24
return time.Duration(v) * tick
}
// Nanospin spins the CPU without calling into the kernel code if possible.
func Nanospin(t time.Duration) {
start := ReadTime()
if start == 0 {
// Use the slow generic version.
cpu.Nanospin(t)
return
}
for ReadTime()-start < t {
}
}
//
const (
// 31:3 reserved
timerPLL6 timerCtrl = 2 << 1 // CONT64_CLK_SRC_SEL; OSC24M if not set;
timerReadLatchEnable timerCtrl = 1 << 1 // CONT64_RLATCH_EN; 1 to latch the counter to the registers
timerClear = 1 << 0 // CONT64_CLR_EN; clears the counter
)
// R8: Page 96
type timerCtrl uint32
// timerMap is the mapping of important registers across CPUs.
type timerMap struct {
reserved0 [0x80 / 4]uint32 //
cntCtl timerCtrl // 0x80 AVS_CNT_CTL_REG AVS Control Register
cnt0 uint32 // 0x84 AVS_CNT0_REG AVS Counter 0 Register
cnt1 uint32 // 0x88 AVS_CNT1_REG AVS Counter 1 Register
cndDrv uint32 // 0x8C AVS_CNT_DIV_REG AVS Divisor Register
reserved1 [0x10 / 4]uint32 // On R8 only.
counterCtrl timerCtrl // 0x0A0 COUNTER64_CTRL_REG 64-bit Counter control
counterLow uint32 // 0x0A4 COUNTER64_LOW_REG 64-bit Counter low
counterHigh uint32 // 0x0A8 COUNTER64_HI_REG 64-bit Counter high
}
// A64: Page 161.
type timerMapA64 struct {
reserved0 uint32 // 0x0 TMR_IRQ_EN_REG Timer IRQ Enable Register
reserved1 uint32 // 0x4 TMR_IRQ_STA_REG Timer Status Register
reserved2 uint32 // 0x10 TMR0_CTRL_REG Timer 0 Control Register
reserved3 uint32 // 0x14 TMR0_INTV_VALUE_REG Timer 0 Interval Value Register
reserved4 uint32 // 0x18 TMR0_CUR_VALUE_REG Timer 0 Current Value Register
reserved5 uint32 // 0x20 TMR1_CTRL_REG Timer 1 Control Register
reserved6 uint32 // 0x24 TMR1_INTV_VALUE_REG Timer 1 Interval Value Register
reserved7 uint32 // 0x28 TMR1_CUR_VALUE_REG Timer 1 Current Value Register
cntCtl timerCtrl // 0x80 AVS_CNT_CTL_REG AVS Control Register
cnt0 uint32 // 0x84 AVS_CNT0_REG AVS Counter 0 Register
cnt1 uint32 // 0x88 AVS_CNT1_REG AVS Counter 1 Register
cndDrv uint32 // 0x8C AVS_CNT_DIV_REG AVS Divisor Register
reserved8 uint32 // 0xA0 WDOG0_IRQ_EN_REG Watchdog 0 IRQ Enable Register
reserved9 uint32 // 0xA4 WDOG0_IRQ_STA_REG Watchdog 0 Status Register
reserved10 uint32 // 0xB0 WDOG0_CTRL_REG Watchdog 0 Control Register
reserved11 uint32 // 0xB4 WDOG0_CFG_REG Watchdog 0 Configuration Register
reserved12 uint32 // 0xB8 WDOG0_MODE_REG Watchdog 0 Mode Register
}
// R8: Page 85
type timerMapR8 struct {
reserved0 uint32 // 0x000 ASYNC_TMR_IRQ_EN_REG Timer IRQ Enable
reserved1 uint32 // 0x004 ASYNC_TMR_IRQ_STAS_REG Timer Status
reserved2 [2]uint32 // 0x008-0x00C
reserved3 uint32 // 0x010 ASYNC_TMR0_CTRL_REG Timer 0 Control
reserved4 uint32 // 0x014 ASYNC_TMR0_INTV_VALUE_REG Timer 0 Interval Value
reserved5 uint32 // 0x018 ASYNC_TMR0_CURNT_VALUE_REG Timer 0 Current Value
reserved6 uint32 // 0x01C
reserved7 uint32 // 0x020 ASYNC_TMR1_CTRL_REG Timer 1 Control
reserved8 uint32 // 0x024 ASYNC_TMR1_INTV_VALUE_REG Timer 1 Interval Value
reserved9 uint32 // 0x028 ASYNC_TMR1_CURNT_VALUE_REG Timer 1 Current Value
reserved10 uint32 // 0x02C
reserved11 uint32 // 0x030 ASYNC_TMR2_CTRL_REG Timer 2 Control
reserved12 uint32 // 0x034 ASYNC_TMR2_INTV_VALUE_REG Timer 2 Interval Value
reserved13 uint32 // 0x038 ASYNC_TMR2_CURNT_VALUE_REG Timer 2 Current Value
reserved14 uint32 // 0x03C
reserved15 uint32 // 0x040 ASYNC_TMR3_CTRL_REG Timer 3 Control
reserved16 uint32 // 0x044 ASYNC_TMR3_INTV_VALUE_REG Timer 3 Interval Value
reserved17 [2]uint32 // 0x048-0x04C
reserved18 uint32 // 0x050 ASYNC_TMR4_CTRL_REG Timer 4 Control
reserved19 uint32 // 0x054 ASYNC_TMR4_INTV_VALUE_REG Timer 4 Interval Value
reserved20 uint32 // 0x058 ASYNC_TMR4_CURNT_VALUE_REG Timer 4 Current Value
reserved21 uint32 // 0x05C
reserved22 uint32 // 0x060 ASYNC_TMR5_CTRL_REG Timer 5 Control
reserved23 uint32 // 0x064 ASYNC_TMR5_INTV_VALUE_REG Timer 5 Interval Value
reserved24 uint32 // 0x068 ASYNC_TMR5_CURNT_VALUE_REG Timer 5 Current Value
reserved25 [5]uint32 // 0x06C-0x07C
cntCtl timerCtrl // 0x080 AVS_CNT_CTL_REG AVS Control Register
cnt0 uint32 // 0x084 AVS_CNT0_REG AVS Counter 0 Register
cnt1 uint32 // 0x088 AVS_CNT1_REG AVS Counter 1 Register
cndDiv uint32 // 0x08C AVS_CNT_DIVISOR_REG AVS Divisor
reserved26 uint32 // 0x090 WDOG_CTRL_REG
reserved27 uint32 // 0x094 WDOG_MODE_REG Watchdog Mode
reserved28 [2]uint32 // 0x098-0x09C
counterCtrl timerCtrl // 0x0A0 COUNTER64_CTRL_REG 64-bit Counter control
counterLow uint32 // 0x0A4 COUNTER64_LOW_REG 64-bit Counter low
counterHigh uint32 // 0x0A8 COUNTER64_HI_REG 64-bit Counter high
reserved29 [0x94]uint32 // 0x0AC-0x13C
reserved30 uint32 // 0x140 CPU_CFG_REG CPU configuration register
}

52
vendor/periph.io/x/periph/host/am335x/am335x.go generated vendored Normal file
View File

@ -0,0 +1,52 @@
// 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.
package am335x
import (
"errors"
"strings"
"periph.io/x/periph"
"periph.io/x/periph/host/distro"
)
// Present returns true if a TM AM335x processor is detected.
func Present() bool {
if isArm {
return strings.HasPrefix(distro.DTModel(), "TI AM335x")
}
return false
}
// driver implements periph.Driver.
type driver struct {
}
func (d *driver) String() string {
return "am335x"
}
func (d *driver) Prerequisites() []string {
return nil
}
func (d *driver) After() []string {
return nil
}
func (d *driver) Init() (bool, error) {
if !Present() {
return false, errors.New("am335x CPU not detected")
}
return true, nil
}
func init() {
if isArm {
periph.MustRegister(&drv)
}
}
var drv driver

7
vendor/periph.io/x/periph/host/am335x/am335x_arm.go generated vendored Normal file
View File

@ -0,0 +1,7 @@
// 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.
package am335x
const isArm = true

View File

@ -0,0 +1,9 @@
// 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.
// +build !arm
package am335x
const isArm = false

28
vendor/periph.io/x/periph/host/am335x/doc.go generated vendored Normal file
View File

@ -0,0 +1,28 @@
// 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.
// Package am335x exposes functionality for the Texas Instruments Sitara AM335x
// processor family.
//
// This processor family is found on the BeagleBone. PRU-ICSS functionality is
// implemented in package pru.
//
// The GPIO pins of the AM335x CPU are grouped into 3 groups of 32 pins: GPIO0,
// GPIO1, and GPIO2. The CPU documentation refers to GPIO in the form of
// GPIOx_y. To get the absolute number, as exposed by sysfs, use 32*x+y to get
// the absolute number.
//
// Datasheet
//
// Technical Reference Manual
// https://www.ti.com/lit/ug/spruh73p/spruh73p.pdf
//
// Other
//
// Marketing page
// https://www.ti.com/processors/sitara/arm-cortex-a8/am335x/overview.html
//
// Family overview
// https://www.ti.com/lit/ds/symlink/am3359.pdf
package am335x

View File

@ -0,0 +1,7 @@
// 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 bcm283x
const isArm = true

View File

@ -0,0 +1,9 @@
// 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.
// +build arm64
package bcm283x
const isArm = true

View File

@ -0,0 +1,9 @@
// 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.
// +build !arm,!arm64
package bcm283x
const isArm = false

330
vendor/periph.io/x/periph/host/bcm283x/clock.go generated vendored Normal file
View File

@ -0,0 +1,330 @@
// 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.
package bcm283x
import (
"errors"
"fmt"
"strings"
"time"
"periph.io/x/periph/conn/physic"
)
// errClockRegister is returned in a situation where the clock memory is not
// working as expected. It is mocked in tests.
var errClockRegister = errors.New("can't write to clock divisor CPU register")
// Clock sources frequency in hertz.
const (
clk19dot2MHz = 19200 * physic.KiloHertz
clk500MHz = 500 * physic.MegaHertz
)
const (
// 31:24 password
clockPasswdCtl clockCtl = 0x5A << 24 // PASSWD
// 23:11 reserved
clockMashMask clockCtl = 3 << 9 // MASH
clockMash0 clockCtl = 0 << 9 // src_freq / divI (ignores divF)
clockMash1 clockCtl = 1 << 9
clockMash2 clockCtl = 2 << 9
clockMash3 clockCtl = 3 << 9 // will cause higher spread
clockFlip clockCtl = 1 << 8 // FLIP
clockBusy clockCtl = 1 << 7 // BUSY
// 6 reserved
clockKill clockCtl = 1 << 5 // KILL
clockEnable clockCtl = 1 << 4 // ENAB
clockSrcMask clockCtl = 0xF << 0 // SRC
clockSrcGND clockCtl = 0 // 0Hz
clockSrc19dot2MHz clockCtl = 1 // 19.2MHz
clockSrcTestDebug0 clockCtl = 2 // 0Hz
clockSrcTestDebug1 clockCtl = 3 // 0Hz
clockSrcPLLA clockCtl = 4 // 0Hz
clockSrcPLLC clockCtl = 5 // 1000MHz (changes with overclock settings)
clockSrcPLLD clockCtl = 6 // 500MHz
clockSrcHDMI clockCtl = 7 // 216MHz; may be disabled
// 8-15 == GND.
)
// clockCtl controls the clock properties.
//
// It must not be changed while busy is set or a glitch may occur.
//
// Page 107
type clockCtl uint32
func (c clockCtl) String() string {
var out []string
if c&0xFF000000 == clockPasswdCtl {
c &^= 0xFF000000
out = append(out, "PWD")
}
switch c & clockMashMask {
case clockMash1:
out = append(out, "Mash1")
case clockMash2:
out = append(out, "Mash2")
case clockMash3:
out = append(out, "Mash3")
default:
}
c &^= clockMashMask
if c&clockFlip != 0 {
out = append(out, "Flip")
c &^= clockFlip
}
if c&clockBusy != 0 {
out = append(out, "Busy")
c &^= clockBusy
}
if c&clockKill != 0 {
out = append(out, "Kill")
c &^= clockKill
}
if c&clockEnable != 0 {
out = append(out, "Enable")
c &^= clockEnable
}
switch x := c & clockSrcMask; x {
case clockSrcGND:
out = append(out, "GND(0Hz)")
case clockSrc19dot2MHz:
out = append(out, "19.2MHz")
case clockSrcTestDebug0:
out = append(out, "Debug0(0Hz)")
case clockSrcTestDebug1:
out = append(out, "Debug1(0Hz)")
case clockSrcPLLA:
out = append(out, "PLLA(0Hz)")
case clockSrcPLLC:
out = append(out, "PLLD(1000MHz)")
case clockSrcPLLD:
out = append(out, "PLLD(500MHz)")
case clockSrcHDMI:
out = append(out, "HDMI(216MHz)")
default:
out = append(out, fmt.Sprintf("GND(%d)", x))
}
c &^= clockSrcMask
if c != 0 {
out = append(out, fmt.Sprintf("clockCtl(0x%0x)", uint32(c)))
}
return strings.Join(out, "|")
}
const (
// 31:24 password
clockPasswdDiv clockDiv = 0x5A << 24 // PASSWD
// Integer part of the divisor
clockDiviShift = 12
clockDiviMax = (1 << 12) - 1
clockDiviMask clockDiv = clockDiviMax << clockDiviShift // DIVI
// Fractional part of the divisor
clockDivfMask clockDiv = (1 << 12) - 1 // DIVF
)
// clockDiv is a 12.12 fixed point value.
//
// The fractional part generates a significant amount of noise so it is
// preferable to not use it.
//
// Page 108
type clockDiv uint32
func (c clockDiv) String() string {
i := (c & clockDiviMask) >> clockDiviShift
c &^= clockDiviMask
if c == 0 {
return fmt.Sprintf("%d.0", i)
}
return fmt.Sprintf("%d.(%d/%d)", i, c, clockDiviMax)
}
// clock is a pair of clockCtl / clockDiv.
//
// It can be set to one of the sources: clockSrc19dot2MHz(19.2MHz) and
// clockSrcPLLD(500Mhz), then divided to a value to get the resulting clock.
// Per spec the resulting frequency should be under 25Mhz.
type clock struct {
ctl clockCtl
div clockDiv
}
// findDivisorExact finds the clock divisor and wait cycles to reduce src to
// desired hz.
//
// The clock divisor is capped to clockDiviMax.
//
// Returns clock divisor, wait cycles. Returns 0, 0 if no exact match is found.
// Favorizes high clock divisor value over high clock wait cycles. This means
// that the function is slower than it could be, but results in more stable
// clock.
func findDivisorExact(src, desired physic.Frequency, maxWaitCycles uint32) (uint32, uint32) {
if src < desired || src%desired != 0 || src/physic.Frequency(maxWaitCycles*clockDiviMax) > desired {
// Can't attain without oversampling (too low) or desired frequency is
// higher than the source (too high) or is not a multiple.
return 0, 0
}
factor := uint32(src / desired)
// TODO(maruel): Only iterate over valid divisors to save a bit more
// calculations. Since it's is only doing 32 loops, this is not a big deal.
for wait := uint32(1); wait <= maxWaitCycles; wait++ {
if rest := factor % wait; rest != 0 {
continue
}
clk := factor / wait
if clk == 0 {
break
}
if clk <= clockDiviMax {
return clk, wait
}
}
return 0, 0
}
// findDivisorOversampled tries to find the lowest allowed oversampling to make
// desiredHz a multiple of srcHz.
//
// Allowed oversampling depends on the desiredHz. Cap oversampling because
// oversampling at 10x in the 1Mhz range becomes unreasonable in term of
// memory usage.
func findDivisorOversampled(src, desired physic.Frequency, maxWaitCycles uint32) (uint32, uint32, physic.Frequency) {
//log.Printf("findDivisorOversampled(%s, %s, %d)", src, desired, maxWaitCycles)
// There are 2 reasons:
// - desired is so low it is not possible to lower src to this frequency
// - not a multiple, there's a need for a prime number
// TODO(maruel): Rewrite without a loop, this is not needed. Leverage primes
// to reduce the number of iterations.
for multiple := physic.Frequency(2); ; multiple++ {
n := multiple * desired
if n > 100*physic.KiloHertz && multiple > 10 {
break
}
if clk, wait := findDivisorExact(src, n, maxWaitCycles); clk != 0 {
return clk, wait, n
}
}
return 0, 0, 0
}
// calcSource choose the best source to get the exact desired clock.
//
// It calculates the clock source, the clock divisor and the wait cycles, if
// applicable. Wait cycles is 'div minus 1'.
func calcSource(f physic.Frequency, maxWaitCycles uint32) (clockCtl, uint32, uint32, physic.Frequency, error) {
if f < physic.Hertz {
return 0, 0, 0, 0, fmt.Errorf("bcm283x-clock: desired frequency %s must be >1hz", f)
}
if f > 125*physic.MegaHertz {
return 0, 0, 0, 0, fmt.Errorf("bcm283x-clock: desired frequency %s is too high", f)
}
// http://elinux.org/BCM2835_datasheet_errata states that clockSrc19dot2MHz
// is the cleanest clock source so try it first.
div, wait := findDivisorExact(clk19dot2MHz, f, maxWaitCycles)
if div != 0 {
return clockSrc19dot2MHz, div, wait, f, nil
}
// Try 500Mhz.
div, wait = findDivisorExact(clk500MHz, f, maxWaitCycles)
if div != 0 {
return clockSrcPLLD, div, wait, f, nil
}
// Try with up to 10x oversampling. This is generally useful for lower
// frequencies, below 10kHz. Prefer the one with less oversampling. Only for
// non-aliased matches.
div19, wait19, f19 := findDivisorOversampled(clk19dot2MHz, f, maxWaitCycles)
div500, wait500, f500 := findDivisorOversampled(clk500MHz, f, maxWaitCycles)
if div19 != 0 && (div500 == 0 || f19 < f500) {
return clockSrc19dot2MHz, div19, wait19, f19, nil
}
if div500 != 0 {
return clockSrcPLLD, div500, wait500, f500, nil
}
return 0, 0, 0, 0, errors.New("failed to find a good clock")
}
// set changes the clock frequency to the desired value or the closest one
// otherwise.
//
// f=0 means disabled.
//
// maxWaitCycles is the maximum oversampling via an additional wait cycles that
// can further divide the clock. Use 1 if no additional wait cycle is
// available. It is expected to be dmaWaitcyclesMax+1.
//
// Returns the actual clock used and divisor.
func (c *clock) set(f physic.Frequency, maxWaitCycles uint32) (physic.Frequency, uint32, error) {
if f == 0 {
c.ctl = clockPasswdCtl | clockKill
for c.ctl&clockBusy != 0 {
}
return 0, 0, nil
}
ctl, div, div2, actual, err := calcSource(f, maxWaitCycles)
if err != nil {
return 0, 0, err
}
return actual, div2, c.setRaw(ctl, div)
}
// setRaw sets the clock speed with the clock source and the divisor.
func (c *clock) setRaw(ctl clockCtl, div uint32) error {
if div < 1 || div > clockDiviMax {
return errors.New("invalid clock divisor")
}
if ctl != clockSrc19dot2MHz && ctl != clockSrcPLLD {
return errors.New("invalid clock control")
}
// Stop the clock.
// TODO(maruel): Do not stop the clock if the current clock rate is the one
// desired.
for c.ctl&clockBusy != 0 {
c.ctl = clockPasswdCtl | clockKill
}
d := clockDiv(div << clockDiviShift)
c.div = clockPasswdDiv | d
Nanospin(10 * time.Nanosecond)
// Page 107
c.ctl = clockPasswdCtl | ctl
Nanospin(10 * time.Nanosecond)
c.ctl = clockPasswdCtl | ctl | clockEnable
if c.div != d {
// This error is mocked out in tests, so the code path of set() callers can
// follow on.
return errClockRegister
}
return nil
}
func (c *clock) String() string {
return fmt.Sprintf("%s / %s", c.ctl, c.div)
}
// clockMap is the memory mapped clock registers.
//
// The clock #1 must not be touched since it is being used by the ethernet
// controller.
//
// Page 107 for gp0~gp2.
// https://scribd.com/doc/127599939/BCM2835-Audio-clocks for PCM/PWM.
type clockMap struct {
reserved0 [0x70 / 4]uint32 //
gp0 clock // CM_GP0CTL+CM_GP0DIV; 0x70-0x74 (125MHz max)
gp1ctl uint32 // CM_GP1CTL+CM_GP1DIV; 0x78-0x7A must not use (used by ethernet)
gp1div uint32 // CM_GP1CTL+CM_GP1DIV; 0x78-0x7A must not use (used by ethernet)
gp2 clock // CM_GP2CTL+CM_GP2DIV; 0x80-0x84 (125MHz max)
reserved1 [(0x98 - 0x88) / 4]uint32 // 0x88-0x94
pcm clock // CM_PCMCTL+CM_PCMDIV 0x98-0x9C
pwm clock // CM_PWMCTL+CM_PWMDIV 0xA0-0xA4
}
func (c *clockMap) GoString() string {
return fmt.Sprintf(
"{\n gp0: %s,\n gp1: %s,\n gp2: %s,\n pcm: %sw,\n pwm: %s,\n}",
&c.gp0, &clock{clockCtl(c.gp1ctl), clockDiv(c.gp1div)}, &c.gp2, &c.pcm, &c.pwm)
}

1224
vendor/periph.io/x/periph/host/bcm283x/dma.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

42
vendor/periph.io/x/periph/host/bcm283x/doc.go generated vendored Normal file
View File

@ -0,0 +1,42 @@
// 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 bcm283x exposes the BCM283x GPIO functionality.
//
// This driver implements memory-mapped GPIO pin manipulation and leverages
// sysfs-gpio for edge detection.
//
// If you are looking for the actual implementation, open doc.go for further
// implementation details.
//
// GPIOs
//
// Aliases for GPCLK0, GPCLK1, GPCLK2 are created for corresponding CLKn pins.
// Same for PWM0_OUT and PWM1_OUT, which point respectively to PWM0 and PWM1.
//
// Datasheet
//
// https://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf
//
// Its crowd-sourced errata: http://elinux.org/BCM2835_datasheet_errata
//
// BCM2836:
// https://www.raspberrypi.org/documentation/hardware/raspberrypi/bcm2836/QA7_rev3.4.pdf
//
// Another doc about PCM and PWM:
// https://scribd.com/doc/127599939/BCM2835-Audio-clocks
//
// GPIO pad control:
// https://scribd.com/doc/101830961/GPIO-Pads-Control2
package bcm283x
// Other implementations details
//
// mainline:
// https://github.com/torvalds/linux/blob/master/drivers/dma/bcm2835-dma.c
// https://github.com/torvalds/linux/blob/master/drivers/gpio
//
// Raspbian kernel:
// https://github.com/raspberrypi/linux/blob/rpi-4.11.y/drivers/dma
// https://github.com/raspberrypi/linux/blob/rpi-4.11.y/drivers/gpio

1361
vendor/periph.io/x/periph/host/bcm283x/gpio.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

234
vendor/periph.io/x/periph/host/bcm283x/pcm.go generated vendored Normal file
View File

@ -0,0 +1,234 @@
// 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
}

272
vendor/periph.io/x/periph/host/bcm283x/pwm.go generated vendored Normal file
View File

@ -0,0 +1,272 @@
// 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.
package bcm283x
import (
"errors"
"fmt"
"time"
"periph.io/x/periph/conn/physic"
)
// PWENi is used to enable/disable the corresponding channel. Setting this bit
// to 1 enables the channel and transmitter state machine. All registers and
// FIFO is writable without setting this bit.
//
// MODEi bit is used to determine mode of operation. Setting this bit to 0
// enables PWM mode. In this mode data stored in either PWM_DATi or FIFO is
// transmitted by pulse width modulation within the range defined by PWM_RNGi.
// When this mode is used MSENi defines whether to use PWM algorithm. Setting
// MODEi to 1 enables serial mode, in which data stored in either PWM_DATi or
// FIFO is transmitted serially within the range defined by PWM_RNGi. Data is
// transmitted MSB first and truncated or zeropadded depending on PWM_RNGi.
// Default mode is PWM.
//
// RPTLi is used to enable/disable repeating of the last data available in the
// FIFO just before it empties. When this bit is 1 and FIFO is used, the last
// available data in the FIFO is repeatedly sent. This may be useful in PWM
// mode to avoid duty cycle gaps. If the FIFO is not used this bit does not
// have any effect. Default operation is do-notrepeat.
//
// SBITi defines the state of the output when no transmission takes place. It
// also defines the zero polarity for the zero padding in serialiser mode. This
// bit is padded between two consecutive transfers as well as tail of the data
// when PWM_RNGi is larger than bit depth of data being transferred. this bit
// is zero by default.
//
// POLAi is used to configure the polarity of the output bit. When set to high
// the final output is inverted. Default operation is no inversion.
//
// USEFi bit is used to enable/disable FIFO transfer. When this bit is high
// data stored in the FIFO is used for transmission. When it is low, data
// written to PWM_DATi is transferred. This bit is 0 as default.
//
// CLRF is used to clear the FIFO. Writing a 1 to this bit clears the FIFO.
// Writing 0 has no effect. This is a single shot operation and reading the bit
// always returns 0.
//
// MSENi is used to determine whether to use PWM algorithm or simple M/S ratio
// transmission. When this bit is high M/S transmission is used. This bit is
// zero as default. When MODEi is 1, this configuration bit has no effect.
//
// See page 139-140 for the description of the PWM and M/S ratio algorithms.
const (
// 31:16 reserved
pwm2MS pwmControl = 1 << 15 // MSEN2; 0: PWM algorithm is used; 1: M/S transmission is used
// 14 reserved
pwm2UseFIFO pwmControl = 1 << 13 // USEF2; 0: Data register is transmitted; 1: Fifo is used for transmission
pwm2Polarity pwmControl = 1 << 12 // POLA2; 0: 0=low 1=high; 1: 1=low 0=high
pwm2SilenceHigh pwmControl = 1 << 11 // SBIT2; Defines the state of the output when no transmission takes place
pwm2RepeatLastData pwmControl = 1 << 10 // RPTL2; 0: Transmission interrupts when FIFO is empty; 1: Last data in FIFO is transmitted repetedly until FIFO is not empty
pwm2Serialiser pwmControl = 1 << 9 // MODE2; 0: PWM mode; 1: Serialiser mode
pwm2Enable pwmControl = 1 << 8 // PWEN2; Enable channel 2
pwm2Mask pwmControl = pwm2MS | pwm2UseFIFO | pwm2Polarity | pwm2SilenceHigh | pwm2RepeatLastData | pwm2Serialiser | pwm2Enable
pwm1MS pwmControl = 1 << 7 // MSEN1; 0: PWM algorithm is used; 1: M/S transmission is used
pwmClearFIFO pwmControl = 1 << 6 // CLRF1; Clear the fifo
pwm1UseFIFO pwmControl = 1 << 5 // USEF1; 0: Data register is transmitted; 1: Fifo is used for transmission
pwm1Polarity pwmControl = 1 << 4 // POLA1; 0: 0=low 1=high; 1: 1=low 0=high
pwm1SilenceHigh pwmControl = 1 << 3 // SBIT1; Defines the state of the output when no transmission takes place
pwm1RepeatLastData pwmControl = 1 << 2 // RPTL1; 0: Transmission interrupts when FIFO is empty; 1: Last data in FIFO is transmitted repetedly until FIFO is not empty
pwm1Serialiser pwmControl = 1 << 1 // MODE1; 0: PWM mode; 1: Serialiser mode
pwm1Enable pwmControl = 1 << 0 // PWEN1; Enable channel 1
pwm1Mask pwmControl = pwm1MS | pwm1UseFIFO | pwm1Polarity | pwm1SilenceHigh | pwm1RepeatLastData | pwm1Serialiser | pwm1Enable
)
// Pages 141-143.
type pwmControl uint32
const (
// 31:13 reserved
// STAi bit indicates the current state of the channel which is useful for
// debugging purposes. The bit set means the channel is currently
// transmitting data.
pwmSta4 pwmStatus = 1 << 12 // STA4
pwmSta3 pwmStatus = 1 << 11 // STA3
pwmSta2 pwmStatus = 1 << 10 // STA2
pwmSta1 pwmStatus = 1 << 9 // STA1
// BERR sets to high when an error has occurred while writing to registers
// via APB. This may happen if the bus tries to write successively to same
// set of registers faster than the synchroniser block can cope with.
// Multiple switching may occur and contaminate the data during
// synchronisation. Software should clear this bit by writing 1. Writing 0
// to this bit has no effect.
pwmBusErr pwmStatus = 1 << 8 // BERR Bus Error flag
// GAPOi. bit indicates that there has been a gap between transmission of two
// consecutive data from FIFO. This may happen when FIFO gets empty after
// state machine has sent a word and waits for the next. If control bit RPTLi
// is set to high this event will not occur. Software must clear this bit by
// writing 1. Writing 0 to this bit has no effect.
pwmGapo4 pwmStatus = 1 << 7 // GAPO4 Channel 4 Gap Occurred flag
pwmGapo3 pwmStatus = 1 << 6 // GAPO3 Channel 3 Gap Occurred flag
pwmGapo2 pwmStatus = 1 << 5 // GAPO2 Channel 2 Gap Occurred flag
pwmGapo1 pwmStatus = 1 << 4 // GAPO1 Channel 1 Gap Occurred flag
// RERR1 bit sets to high when a read when empty error occurs. Software must
// clear this bit by writing 1. Writing 0 to this bit has no effect.
pwmRerr1 pwmStatus = 1 << 3 // RERR1
// WERR1 bit sets to high when a write when full error occurs. Software must
// clear this bit by writing 1. Writing 0 to this bit has no effect.
pwmWerr1 pwmStatus = 1 << 2 // WERR1
// EMPT1 bit indicates the empty status of the FIFO. If this bit is high FIFO
// is empty.
pwmEmpt1 pwmStatus = 1 << 1 // EMPT1
// FULL1 bit indicates the full status of the FIFO. If this bit is high FIFO
// is full.
pwmFull1 pwmStatus = 1 << 0 // FULL1
pwmStatusMask = pwmSta4 | pwmSta3 | pwmSta2 | pwmSta1 | pwmBusErr | pwmGapo4 | pwmGapo3 | pwmGapo2 | pwmGapo1 | pwmRerr1 | pwmWerr1 | pwmEmpt1 | pwmFull1
)
// Pages 144-145.
type pwmStatus uint32
const (
pwmDMAEnable pwmDMACfg = 1 << 31 // ENAB
// 30:16 reserved
pwmPanicShift = 16
pwmPanicMask pwmDMACfg = 0xFF << pwmPanicShift // PANIC Default is 7
pwmDreqMask pwmDMACfg = 0xFF // DREQ Default is 7
)
// Page 145.
type pwmDMACfg uint32
// pwmMap is the block to control the PWM generator.
//
// Note that pins are named PWM0 and PWM1 but the mapping uses channel numbers
// 1 and 2.
// - PWM0: GPIO12, GPIO18, GPIO40, GPIO52.
// - PWM1: GPIO13, GPIO19, GPIO41, GPIO45, GPIO53.
//
// Each channel works independently. They can either output a bitstream or a
// serialised version of up to eight 32 bits words.
//
// The default base PWM frequency is 100Mhz.
//
// Description at page 138-139.
//
// Page 140-141.
type pwmMap struct {
ctl pwmControl // CTL
status pwmStatus // STA
dmaCfg pwmDMACfg // DMAC
// This register is used to define the range for the corresponding channel.
// In PWM mode evenly distributed pulses are sent within a period of length
// defined by this register. In serial mode serialised data is transmitted
// within the same period. If the value in PWM_RNGi is less than 32, only the
// first PWM_RNGi bits are sent resulting in a truncation. If it is larger
// than 32 excess zero bits are padded at the end of data. Default value for
// this register is 32.
dummy1 uint32 // Padding
rng1 uint32 // RNG1
// This register stores the 32 bit data to be sent by the PWM Controller when
// USEFi is 0. In PWM mode data is sent by pulse width modulation: the value
// of this register defines the number of pulses which is sent within the
// period defined by PWM_RNGi. In serialiser mode data stored in this
// register is serialised and transmitted.
dat1 uint32 // DAT1
// This register is the FIFO input for the all channels. Data written to this
// address is stored in channel FIFO and if USEFi is enabled for the channel
// i it is used as data to be sent. This register is write only, and reading
// this register will always return bus default return value, pwm0.
// When more than one channel is enabled for FIFO usage, the data written
// into the FIFO is shared between these channels in turn. For example if the
// word series A B C D E F G H I .. is written to FIFO and two channels are
// active and configured to use FIFO then channel 1 will transmit words A C E
// G I .. and channel 2 will transmit words B D F H .. . Note that
// requesting data from the FIFO is in locked-step manner and therefore
// requires tight coupling of state machines of the channels. If any of the
// channel range (period) value is different than the others this will cause
// the channels with small range values to wait between words hence resulting
// in gaps between words. To avoid that, each channel sharing the FIFO should
// be configured to use the same range value. Also note that RPTLi are not
// meaningful when the FIFO is shared between channels as there is no defined
// channel to own the last data in the FIFO. Therefore sharing channels must
// have their RPTLi set to zero.
//
// If the set of channels to share the FIFO has been modified after a
// configuration change, FIFO should be cleared before writing new data.
fifo uint32 // FIF1
dummy2 uint32 // Padding
rng2 uint32 // RNG2 Equivalent of rng1 for channel 2
dat2 uint32 // DAT2 Equivalent of dat1 for channel 2
}
// reset stops the PWM.
func (p *pwmMap) reset() {
p.dmaCfg = 0
p.ctl |= pwmClearFIFO
p.ctl &^= pwm1Enable | pwm2Enable
Nanospin(100 * time.Microsecond) // Cargo cult copied. Probably not necessary.
p.status = pwmBusErr | pwmGapo1 | pwmGapo2 | pwmGapo3 | pwmGapo4 | pwmRerr1 | pwmWerr1
Nanospin(100 * time.Microsecond)
// Use the full 32 bits of DATi.
p.rng1 = 32
p.rng2 = 32
}
// setPWMClockSource sets the PWM clock for use by the DMA controller for
// pacing.
//
// It may select an higher frequency than the one requested.
//
// Other potentially good clock sources are PCM, SPI and UART.
func setPWMClockSource() (physic.Frequency, error) {
if drvDMA.pwmMemory == nil {
return 0, errors.New("subsystem PWM not initialized")
}
if drvDMA.clockMemory == nil {
return 0, errors.New("subsystem Clock not initialized")
}
if drvDMA.pwmDMACh != nil {
// Already initialized
return drvDMA.pwmDMAFreq, nil
}
// divs * div must fit in rng1 registor.
div := uint32(drvDMA.pwmBaseFreq / drvDMA.pwmDMAFreq)
actual, divs, err := drvDMA.clockMemory.pwm.set(drvDMA.pwmBaseFreq, div)
if err != nil {
return 0, err
}
if e := actual / physic.Frequency(divs*div); drvDMA.pwmDMAFreq != e {
return 0, fmt.Errorf("unexpected DMA frequency %s != %s (%d/%d/%d)", drvDMA.pwmDMAFreq, e, actual, divs, div)
}
// It acts as a clock multiplier, since this amount of data is sent per
// clock tick.
drvDMA.pwmMemory.rng1 = divs * div
Nanospin(10 * time.Microsecond)
// Periph data (?)
// Use low priority.
drvDMA.pwmMemory.dmaCfg = pwmDMAEnable | pwmDMACfg(15<<pwmPanicShift|15)
Nanospin(10 * time.Microsecond)
drvDMA.pwmMemory.ctl |= pwmClearFIFO
Nanospin(10 * time.Microsecond)
old := drvDMA.pwmMemory.ctl
drvDMA.pwmMemory.ctl = (old & ^pwmControl(0xff)) | pwm1UseFIFO | pwm1Enable
// Start DMA
if drvDMA.pwmDMACh, drvDMA.pwmDMABuf, err = dmaWritePWMFIFO(); err != nil {
return 0, err
}
return drvDMA.pwmDMAFreq, nil
}
func resetPWMClockSource() error {
if drvDMA.pwmDMACh != nil {
drvDMA.pwmDMACh.reset()
drvDMA.pwmDMACh = nil
}
if drvDMA.pwmDMABuf != nil {
if err := drvDMA.pwmDMABuf.Close(); err != nil {
return err
}
drvDMA.pwmDMABuf = nil
}
_, _, err := drvDMA.clockMemory.pwm.set(0, 0)
return err
}

134
vendor/periph.io/x/periph/host/bcm283x/streams.go generated vendored Normal file
View File

@ -0,0 +1,134 @@
// 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.
package bcm283x
import (
"encoding/binary"
"errors"
"fmt"
"periph.io/x/periph/conn/gpio/gpiostream"
)
// uint32ToBitLSBF packs a bit offset found on slice `d` (that is actually
// uint32) back into a densely packed Bits stream.
func uint32ToBitLSBF(w []byte, d []uint8, bit uint8, skip int) {
// Little endian.
x := bit / 8
d = d[x:]
bit -= 8 * x
mask := uint8(1) << bit
for i := range w {
w[i] = ((d[0]&mask)>>bit<<0 |
(d[skip*1]&mask)>>bit<<1 |
(d[skip*2]&mask)>>bit<<2 |
(d[skip*3]&mask)>>bit<<3 |
(d[skip*4]&mask)>>bit<<4 |
(d[skip*5]&mask)>>bit<<5 |
(d[skip*6]&mask)>>bit<<6 |
(d[skip*7]&mask)>>bit<<7)
d = d[skip*8:]
}
}
func getBit(b byte, index int, msb bool) byte {
var shift uint
if msb {
shift = uint(7 - index)
} else {
shift = uint(index)
}
return (b >> shift) & 1
}
func raster32Bits(s gpiostream.Stream, skip int, clear, set []uint32, mask uint32) error {
var msb bool
var bits []byte
switch b := s.(type) {
case *gpiostream.BitStream:
msb = !b.LSBF
bits = b.Bits
default:
return fmt.Errorf("unsupported type %T", b)
}
m := len(clear) / 8
if n := len(bits); n < m {
m = n
}
index := 0
for i := 0; i < m; i++ {
for j := 0; j < 8; j++ {
if getBit(bits[i], j, msb) != 0 {
for k := 0; k < skip; k++ {
set[index] |= mask
index++
}
} else {
for k := 0; k < skip; k++ {
clear[index] |= mask
index++
}
}
}
}
return nil
}
// raster32 rasters the stream into a uint32 stream with the specified masks to
// put in the correctly slice when the bit is set and when it is clear.
//
// `s` must be one of the types in this package.
func raster32(s gpiostream.Stream, skip int, clear, set []uint32, mask uint32) error {
if mask == 0 {
return errors.New("bcm283x: mask is 0")
}
if len(clear) == 0 {
return errors.New("bcm283x: clear buffer is empty")
}
if len(set) == 0 {
return errors.New("bcm283x: set buffer is empty")
}
if len(clear) != len(set) {
return errors.New("bcm283x: clear and set buffers have different length")
}
switch x := s.(type) {
case *gpiostream.BitStream:
// TODO
return raster32Bits(x, skip, clear, set, mask)
case *gpiostream.EdgeStream:
return errors.New("bcm283x: EdgeStream is not supported yet")
case *gpiostream.Program:
return errors.New("bcm283x: Program is not supported yet")
default:
return errors.New("bcm283x: unknown stream type")
}
}
// PCM/PWM DMA buf is encoded as little-endian and MSB first.
func copyStreamToDMABuf(w gpiostream.Stream, dst []uint32) error {
switch v := w.(type) {
case *gpiostream.BitStream:
if v.LSBF {
return errors.New("TODO(simokawa): handle BitStream.LSBF")
}
// This is big-endian and MSB first.
i := 0
for ; i < len(v.Bits)/4; i++ {
dst[i] = binary.BigEndian.Uint32(v.Bits[i*4:])
}
last := uint32(0)
if mod := len(v.Bits) % 4; mod > 0 {
for j := 0; j < mod; j++ {
last |= (uint32(v.Bits[i*4+j])) << uint32(8*(3-j))
}
dst[i] = last
}
return nil
case *gpiostream.EdgeStream:
return errors.New("TODO(simokawa): handle EdgeStream")
default:
return errors.New("unsupported Stream type")
}
}

60
vendor/periph.io/x/periph/host/bcm283x/timer.go generated vendored Normal file
View File

@ -0,0 +1,60 @@
// 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.
package bcm283x
import (
"time"
"periph.io/x/periph/host/cpu"
)
// ReadTime returns the time on a monotonic 1Mhz clock (1µs resolution).
//
// It only works if bcm283x-dma successfully loaded. Otherwise it returns 0.
func ReadTime() time.Duration {
if drvDMA.timerMemory == nil {
return 0
}
return (time.Duration(drvDMA.timerMemory.high)<<32 | time.Duration(drvDMA.timerMemory.low)) * time.Microsecond
}
// Nanospin spins the CPU without calling into the kernel code if possible.
func Nanospin(t time.Duration) {
start := ReadTime()
if start == 0 {
// Use the slow generic version.
cpu.Nanospin(t)
return
}
// TODO(maruel): Optimize code path for sub-1µs duration.
for ReadTime()-start < t {
}
}
//
const (
// 31:4 reserved
timerM3 = 1 << 3 // M3
timerM2 = 1 << 2 // M2
timerM1 = 1 << 1 // M1
timerM0 = 1 << 0 // M0
)
// Page 173
type timerCtl uint32
// timerMap represents the registers to access the 1Mhz timer.
//
// Page 172
type timerMap struct {
ctl timerCtl // CS
low uint32 // CLO
high uint32 // CHI
c0 uint32 // 0
c1 uint32 // C1
c2 uint32 // C2
c3 uint32 // C3
}

34
vendor/periph.io/x/periph/host/beagle/black/black.go generated vendored Normal file
View File

@ -0,0 +1,34 @@
// Copyright 2018 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 black implements headers for the BeagleBone Black and BeagleBone
// Black Wireless micro-computers.
//
// Reference
//
// https://beagleboard.org/black
//
// Datasheet
//
// https://elinux.org/Beagleboard:BeagleBoneBlack
//
// https://github.com/CircuitCo/BeagleBone-Black/blob/rev_b/BBB_SRM.pdf
//
// https://elinux.org/Beagleboard:Cape_Expansion_Headers
package black
import (
"strings"
"periph.io/x/periph/host/distro"
)
// Present returns true if the host is a BeagleBone Black or BeagleBone Black
// Wireless.
func Present() bool {
if isArm {
return strings.HasPrefix(distro.DTModel(), "TI AM335x BeagleBone Black")
}
return false
}

View File

@ -0,0 +1,7 @@
// Copyright 2018 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 black
const isArm = true

View File

@ -0,0 +1,9 @@
// Copyright 2018 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.
// +build !arm
package black
const isArm = false

318
vendor/periph.io/x/periph/host/beagle/bone/bone.go generated vendored Normal file
View File

@ -0,0 +1,318 @@
// Copyright 2018 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 bone implements headers J1, P8 and P9 found on many (but not all)
// BeagleBone micro-computer.
//
// In particular, the headers are found on the models using a TI AM335x
// processor: BeagleBone Black, Black Wireless, Green and Green Wireless.
//
// Reference
//
// http://beagleboard.org/Support/bone101/#hardware
package bone
import (
"errors"
"periph.io/x/periph"
"periph.io/x/periph/conn/gpio"
"periph.io/x/periph/conn/pin"
"periph.io/x/periph/conn/pin/pinreg"
"periph.io/x/periph/host/beagle/black"
"periph.io/x/periph/host/beagle/green"
"periph.io/x/periph/host/sysfs"
)
// TODO(maruel): Use specialized am335x or pru implementation once available.
// Common pin types on BeagleBones.
var (
PWR_BUT = &pin.BasicPin{N: "PWR_BUT"} //
RESET_OUT = &pin.BasicPin{N: "RESET_OUT"} // SYS_RESETn
VADC = &pin.BasicPin{N: "VADC"} // VDD_ADC
AIN4 = &pin.BasicPin{N: "AIN4"} // AIN4
AGND = &pin.BasicPin{N: "AGND"} // GNDA_ADC
AIN6 = &pin.BasicPin{N: "AIN6"} // AIN6
AIN5 = &pin.BasicPin{N: "AIN5"} // AIN5
AIN2 = &pin.BasicPin{N: "AIN2"} // AIN2
AIN3 = &pin.BasicPin{N: "AIN3"} // AIN3
AIN0 = &pin.BasicPin{N: "AIN0"} // AIN0
AIN1 = &pin.BasicPin{N: "AIN1"} // AIN1
)
// Headers found on BeagleBones.
var (
// Port J1 is the UART port where the default terminal is connected to.
J1_1 pin.Pin = pin.GROUND
J1_2 pin.Pin = pin.INVALID
J1_3 pin.Pin = pin.INVALID
J1_4 gpio.PinIO = gpio.INVALID // GPIO42, UART0_RX
J1_5 gpio.PinIO = gpio.INVALID // GPIO43, UART0_TX
J1_6 pin.Pin = pin.INVALID
P8_1 pin.Pin = pin.GROUND
P8_2 pin.Pin = pin.GROUND
P8_3 gpio.PinIO = gpio.INVALID // GPIO38, MMC1_DAT6
P8_4 gpio.PinIO = gpio.INVALID // GPIO39, MMC1_DAT7
P8_5 gpio.PinIO = gpio.INVALID // GPIO34, MMC1_DAT2
P8_6 gpio.PinIO = gpio.INVALID // GPIO35, MMC1_DAT3
P8_7 gpio.PinIO = gpio.INVALID // GPIO66, Timer4
P8_8 gpio.PinIO = gpio.INVALID // GPIO67, Timer7
P8_9 gpio.PinIO = gpio.INVALID // GPIO69, Timer5
P8_10 gpio.PinIO = gpio.INVALID // GPIO68, Timer6
P8_11 gpio.PinIO = gpio.INVALID // GPIO45,
P8_12 gpio.PinIO = gpio.INVALID // GPIO44,
P8_13 gpio.PinIO = gpio.INVALID // GPIO23, EHRPWM2B
P8_14 gpio.PinIO = gpio.INVALID // GPIO26,
P8_15 gpio.PinIO = gpio.INVALID // GPIO47,
P8_16 gpio.PinIO = gpio.INVALID // GPIO46,
P8_17 gpio.PinIO = gpio.INVALID // GPIO27,
P8_18 gpio.PinIO = gpio.INVALID // GPIO65,
P8_19 gpio.PinIO = gpio.INVALID // GPIO22, EHRPWM2A
P8_20 gpio.PinIO = gpio.INVALID // GPIO63, MMC1_CMD
P8_21 gpio.PinIO = gpio.INVALID // GPIO62, MMC1_CLK
P8_22 gpio.PinIO = gpio.INVALID // GPIO37, MMC1_DAT5
P8_23 gpio.PinIO = gpio.INVALID // GPIO36, MMC1_DAT4
P8_24 gpio.PinIO = gpio.INVALID // GPIO33, MMC1_DAT1
P8_25 gpio.PinIO = gpio.INVALID // GPIO32, MMC1_DAT0
P8_26 gpio.PinIO = gpio.INVALID // GPIO61,
P8_27 gpio.PinIO = gpio.INVALID // GPIO86, LCD_VSYNC
P8_28 gpio.PinIO = gpio.INVALID // GPIO88, LCD_PCLK
P8_29 gpio.PinIO = gpio.INVALID // GPIO87, LCD_HSYNC
P8_30 gpio.PinIO = gpio.INVALID // GPIO89, LCD_AC_BIAS_E
P8_31 gpio.PinIO = gpio.INVALID // GPIO10, LCD_DATA14, UART4_CTS
P8_32 gpio.PinIO = gpio.INVALID // GPIO11, LCD_DATA15, UART5_RTS
P8_33 gpio.PinIO = gpio.INVALID // GPIO9, LCD_DATA13, UART4_RTS
P8_34 gpio.PinIO = gpio.INVALID // GPIO81, LCD_DATA11, EHRPWM1B, UART3_RTS
P8_35 gpio.PinIO = gpio.INVALID // GPIO8, LCD_DATA12, UART4_CTS
P8_36 gpio.PinIO = gpio.INVALID // GPIO80, LCD_DATA10, EHRPWM1A, UART3_CTS
P8_37 gpio.PinIO = gpio.INVALID // GPIO78, LCD_DATA8, UART5_TX
P8_38 gpio.PinIO = gpio.INVALID // GPIO79, LCD_DATA9, UART5_RX
P8_39 gpio.PinIO = gpio.INVALID // GPIO76, LCD_DATA6
P8_40 gpio.PinIO = gpio.INVALID // GPIO77, LCD_DATA7
P8_41 gpio.PinIO = gpio.INVALID // GPIO74, LCD_DATA4
P8_42 gpio.PinIO = gpio.INVALID // GPIO75, LCD_DATA5
P8_43 gpio.PinIO = gpio.INVALID // GPIO72, LCD_DATA2
P8_44 gpio.PinIO = gpio.INVALID // GPIO73, LCD_DATA3
P8_45 gpio.PinIO = gpio.INVALID // GPIO70, LCD_DATA0, EHRPWM2A
P8_46 gpio.PinIO = gpio.INVALID // GPIO71, LCD_DATA1, EHRPWM2B
P9_1 pin.Pin = pin.GROUND
P9_2 pin.Pin = pin.GROUND
P9_3 pin.Pin = pin.V3_3
P9_4 pin.Pin = pin.V3_3
P9_5 pin.Pin = pin.V5
P9_6 pin.Pin = pin.V5
P9_7 pin.Pin = pin.V5
P9_8 pin.Pin = pin.V5
P9_9 pin.Pin = PWR_BUT // PWR_BUT
P9_10 pin.Pin = RESET_OUT // SYS_RESETn
P9_11 gpio.PinIO = gpio.INVALID // GPIO30, UART4_RX
P9_12 gpio.PinIO = gpio.INVALID // GPIO60
P9_13 gpio.PinIO = gpio.INVALID // GPIO31, UART4_TX
P9_14 gpio.PinIO = gpio.INVALID // GPIO50, EHRPWM1A
P9_15 gpio.PinIO = gpio.INVALID // GPIO48
P9_16 gpio.PinIO = gpio.INVALID // GPIO51, EHRPWM1B
P9_17 gpio.PinIO = gpio.INVALID // GPIO5, I2C1_SCL, SPI0_CS0
P9_18 gpio.PinIO = gpio.INVALID // GPIO4, I2C1_SDA, SPI0_MISO
P9_19 gpio.PinIO = gpio.INVALID // GPIO13, I2C2_SCL, UART1_RTS, SPI1_CS1
P9_20 gpio.PinIO = gpio.INVALID // GPIO12, I2C2_SDA, UART1_CTS, SPI1_CS0
P9_21 gpio.PinIO = gpio.INVALID // GPIO3, EHRPWM0B, I2C2_SCL, UART2_TX, SPI0_MOSI
P9_22 gpio.PinIO = gpio.INVALID // GPIO2, EHRPWM0A, I2C2_SDA, UART2_RX, SPI0_CLK
P9_23 gpio.PinIO = gpio.INVALID // GPIO49
P9_24 gpio.PinIO = gpio.INVALID // GPIO15, I2C1_SCL, UART1_TX
P9_25 gpio.PinIO = gpio.INVALID // GPIO117
P9_26 gpio.PinIO = gpio.INVALID // GPIO14, I2C1_SDA, UART1_RX
P9_27 gpio.PinIO = gpio.INVALID // GPIO115
P9_28 gpio.PinIO = gpio.INVALID // GPIO113, ECAPPWM2, SPI1_CS0
P9_29 gpio.PinIO = gpio.INVALID // GPIO111, EHRPWM0B, SPI1_MOSI
P9_30 gpio.PinIO = gpio.INVALID // GPIO112, SPI1_MISO
P9_31 gpio.PinIO = gpio.INVALID // GPIO110, EHRPWM0A, SPI1_CLK
P9_32 pin.Pin = VADC // VDD_ADC
P9_33 pin.Pin = AIN4 // AIN4
P9_34 pin.Pin = AGND // GNDA_ADC
P9_35 pin.Pin = AIN6 // AIN6
P9_36 pin.Pin = AIN5 // AIN5
P9_37 pin.Pin = AIN2 // AIN2
P9_38 pin.Pin = AIN3 // AIN3
P9_39 pin.Pin = AIN0 // AIN0
P9_40 pin.Pin = AIN1 // AIN1
P9_41 gpio.PinIO = gpio.INVALID // GPIO20
P9_42 gpio.PinIO = gpio.INVALID // GPIO7, ECAPPWM0, UART3_TX, SPI1_CS1
P9_43 pin.Pin = pin.GROUND
P9_44 pin.Pin = pin.GROUND
P9_45 pin.Pin = pin.GROUND
P9_46 pin.Pin = pin.GROUND
)
// Present returns true if the host is a BeagleBone Black/Green or their
// Wireless version.
func Present() bool {
return black.Present() || green.Present()
}
// driver implements periph.Driver.
type driver struct {
}
func (d *driver) String() string {
return "beaglebone"
}
func (d *driver) Prerequisites() []string {
return []string{"am335x"}
}
func (d *driver) After() []string {
return nil
}
func (d *driver) Init() (bool, error) {
if !Present() {
return false, errors.New("BeagleBone board not detected")
}
J1_4 = sysfs.Pins[42]
J1_5 = sysfs.Pins[43]
P8_3 = sysfs.Pins[38]
P8_4 = sysfs.Pins[39]
P8_5 = sysfs.Pins[34]
P8_6 = sysfs.Pins[35]
P8_7 = sysfs.Pins[66]
P8_8 = sysfs.Pins[67]
P8_9 = sysfs.Pins[69]
P8_10 = sysfs.Pins[68]
P8_11 = sysfs.Pins[45]
P8_12 = sysfs.Pins[44]
P8_13 = sysfs.Pins[23]
P8_14 = sysfs.Pins[26]
P8_15 = sysfs.Pins[47]
P8_16 = sysfs.Pins[46]
P8_17 = sysfs.Pins[27]
P8_18 = sysfs.Pins[65]
P8_19 = sysfs.Pins[22]
P8_20 = sysfs.Pins[63]
P8_21 = sysfs.Pins[62]
P8_22 = sysfs.Pins[37]
P8_23 = sysfs.Pins[36]
P8_24 = sysfs.Pins[33]
P8_25 = sysfs.Pins[32]
P8_26 = sysfs.Pins[61]
P8_27 = sysfs.Pins[86]
P8_28 = sysfs.Pins[88]
P8_29 = sysfs.Pins[87]
P8_30 = sysfs.Pins[89]
P8_31 = sysfs.Pins[10]
P8_32 = sysfs.Pins[11]
P8_33 = sysfs.Pins[9]
P8_34 = sysfs.Pins[81]
P8_35 = sysfs.Pins[8]
P8_36 = sysfs.Pins[80]
P8_37 = sysfs.Pins[78]
P8_38 = sysfs.Pins[79]
P8_39 = sysfs.Pins[76]
P8_40 = sysfs.Pins[77]
P8_41 = sysfs.Pins[74]
P8_42 = sysfs.Pins[75]
P8_43 = sysfs.Pins[72]
P8_44 = sysfs.Pins[73]
P8_45 = sysfs.Pins[70]
P8_46 = sysfs.Pins[71]
P9_11 = sysfs.Pins[30]
P9_12 = sysfs.Pins[60]
P9_13 = sysfs.Pins[31]
P9_14 = sysfs.Pins[50]
P9_15 = sysfs.Pins[48]
P9_16 = sysfs.Pins[51]
P9_17 = sysfs.Pins[5]
P9_18 = sysfs.Pins[4]
P9_19 = sysfs.Pins[13]
P9_20 = sysfs.Pins[12]
P9_21 = sysfs.Pins[3]
P9_22 = sysfs.Pins[2]
P9_23 = sysfs.Pins[49]
P9_24 = sysfs.Pins[15]
P9_25 = sysfs.Pins[117]
P9_26 = sysfs.Pins[14]
P9_27 = sysfs.Pins[115]
P9_28 = sysfs.Pins[113]
P9_29 = sysfs.Pins[111]
P9_30 = sysfs.Pins[112]
P9_31 = sysfs.Pins[110]
P9_41 = sysfs.Pins[20]
P9_42 = sysfs.Pins[7]
hdr := [][]pin.Pin{{J1_1}, {J1_2}, {J1_3}, {J1_4}, {J1_5}, {J1_6}}
if err := pinreg.Register("J1", hdr); err != nil {
return true, err
}
hdr = [][]pin.Pin{
{P8_1, P8_2},
{P8_3, P8_4},
{P8_5, P8_6},
{P8_7, P8_8},
{P8_9, P8_10},
{P8_11, P8_12},
{P8_13, P8_14},
{P8_15, P8_16},
{P8_17, P8_18},
{P8_19, P8_20},
{P8_21, P8_22},
{P8_23, P8_24},
{P8_25, P8_26},
{P8_27, P8_28},
{P8_29, P8_30},
{P8_31, P8_32},
{P8_33, P8_34},
{P8_35, P8_36},
{P8_37, P8_38},
{P8_39, P8_40},
{P8_41, P8_42},
{P8_43, P8_44},
{P8_45, P8_46},
}
if err := pinreg.Register("P8", hdr); err != nil {
return true, err
}
hdr = [][]pin.Pin{
{P9_1, P9_2},
{P9_3, P9_4},
{P9_5, P9_6},
{P9_7, P9_8},
{P9_9, P9_10},
{P9_11, P9_12},
{P9_13, P9_14},
{P9_15, P9_16},
{P9_17, P9_18},
{P9_19, P9_20},
{P9_21, P9_22},
{P9_23, P9_24},
{P9_25, P9_26},
{P9_27, P9_28},
{P9_29, P9_30},
{P9_31, P9_32},
{P9_33, P9_34},
{P9_35, P9_36},
{P9_37, P9_38},
{P9_39, P9_40},
{P9_41, P9_42},
{P9_43, P9_44},
{P9_45, P9_46},
}
err := pinreg.Register("P9", hdr)
return true, err
}
func init() {
if isArm {
periph.MustRegister(&drv)
}
}
var drv driver

View File

@ -0,0 +1,7 @@
// Copyright 2018 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 bone
const isArm = true

View File

@ -0,0 +1,9 @@
// Copyright 2018 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.
// +build !arm
package bone
const isArm = false

95
vendor/periph.io/x/periph/host/beagle/green/green.go generated vendored Normal file
View File

@ -0,0 +1,95 @@
// Copyright 2018 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 green implements headers for the BeagleBone Green and BeagleBone
// Green Wireless micro-computers.
//
// Reference
//
// https://beagleboard.org/green
//
// https://beagleboard.org/green-wireless
//
// Datasheet
//
// http://wiki.seeedstudio.com/BeagleBone_Green/
package green
import (
"errors"
"strings"
"periph.io/x/periph"
"periph.io/x/periph/conn/gpio"
"periph.io/x/periph/conn/pin"
"periph.io/x/periph/conn/pin/pinreg"
"periph.io/x/periph/host/distro"
"periph.io/x/periph/host/sysfs"
)
// Headers found on BeagleBone Green.
var (
// I2C Groove port.
I2C_SCL gpio.PinIO = gpio.INVALID // GPIO13, I2C2_SCL, UART1_RTS, SPI1_CS1
I2C_SDA gpio.PinIO = gpio.INVALID // GPIO12, I2C2_SDA, UART1_CTS, SPI1_CS0
// UART Groove port connected to UART2.
UART_TX gpio.PinIO = gpio.INVALID // GPIO3, EHRPWM0B, I2C2_SCL, UART2_TX, SPI0_MISO
UART_RX gpio.PinIO = gpio.INVALID // GPIO2, EHRPWM0A, I2C2_SDA, UART2_RX, SPI0_CLK
)
// Present returns true if the host is a BeagleBone Green or BeagleBone Green
// Wireless.
func Present() bool {
if isArm {
return strings.HasPrefix(distro.DTModel(), "TI AM335x BeagleBone Green")
}
return false
}
// driver implements periph.Driver.
type driver struct {
}
func (d *driver) String() string {
return "beaglebone-green"
}
func (d *driver) Prerequisites() []string {
return []string{"am335x"}
}
func (d *driver) After() []string {
return nil
}
func (d *driver) Init() (bool, error) {
if !Present() {
return false, errors.New("BeagleBone Green board not detected")
}
I2C_SDA = sysfs.Pins[12]
I2C_SCL = sysfs.Pins[13]
hdr := [][]pin.Pin{{pin.GROUND}, {pin.V3_3}, {I2C_SDA}, {I2C_SCL}}
if err := pinreg.Register("I2C", hdr); err != nil {
return true, err
}
UART_TX = sysfs.Pins[3]
UART_RX = sysfs.Pins[2]
hdr = [][]pin.Pin{{pin.GROUND}, {pin.V3_3}, {UART_TX}, {UART_RX}}
if err := pinreg.Register("UART", hdr); err != nil {
return true, err
}
return true, nil
}
func init() {
if isArm {
periph.MustRegister(&drv)
}
}
var drv driver

View File

@ -0,0 +1,7 @@
// Copyright 2018 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 green
const isArm = true

View File

@ -0,0 +1,9 @@
// Copyright 2018 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.
// +build !arm
package green
const isArm = false

358
vendor/periph.io/x/periph/host/chip/chip.go generated vendored Normal file
View File

@ -0,0 +1,358 @@
// 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 chip
import (
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
"periph.io/x/periph"
"periph.io/x/periph/conn/gpio"
"periph.io/x/periph/conn/gpio/gpioreg"
"periph.io/x/periph/conn/pin"
"periph.io/x/periph/conn/pin/pinreg"
"periph.io/x/periph/host/allwinner"
"periph.io/x/periph/host/distro"
"periph.io/x/periph/host/fs"
)
// C.H.I.P. hardware pins.
var (
TEMP_SENSOR = &pin.BasicPin{N: "TEMP_SENSOR"}
PWR_SWITCH = &pin.BasicPin{N: "PWR_SWITCH"}
// XIO "gpio" pins attached to the pcf8574 I²C port extender.
XIO0, XIO1, XIO2, XIO3, XIO4, XIO5, XIO6, XIO7 gpio.PinIO
)
// The U13 header is opposite the power LED.
//
// The alternate pin functionality is described at pages 322-323 of
// https://github.com/NextThingCo/CHIP-Hardware/raw/master/CHIP%5Bv1_0%5D/CHIPv1_0-BOM-Datasheets/Allwinner%20R8%20User%20Manual%20V1.1.pdf
var (
U13_1 = pin.GROUND //
U13_2 = pin.DC_IN //
U13_3 = pin.V5 // (filtered)
U13_4 = pin.GROUND //
U13_5 = pin.V3_3 //
U13_6 = TEMP_SENSOR // Analog temp sensor input
U13_7 = pin.V1_8 //
U13_8 = pin.BAT_PLUS // External LiPo battery
U13_9 = allwinner.PB16 // I2C1_SDA
U13_10 = PWR_SWITCH // Power button
U13_11 = allwinner.PB15 // I2C1_SCL
U13_12 = pin.GROUND //
U13_13 = allwinner.X1 // Touch screen X1
U13_14 = allwinner.X2 // Touch screen X2
U13_15 = allwinner.Y1 // Touch screen Y1
U13_16 = allwinner.Y2 // Touch screen Y2
U13_17 = allwinner.PD2 // LCD-D2; UART2_TX firmware probe for 1-wire to detect DIP at boot; http://docs.getchip.com/dip.html#dip-identification
U13_18 = allwinner.PB2 // PWM0; EINT16
U13_19 = allwinner.PD4 // LCD-D4; UART2_CTS
U13_20 = allwinner.PD3 // LCD-D3; UART2_RX
U13_21 = allwinner.PD6 // LCD-D6
U13_22 = allwinner.PD5 // LCD-D5
U13_23 = allwinner.PD10 // LCD-D10
U13_24 = allwinner.PD7 // LCD-D7
U13_25 = allwinner.PD12 // LCD-D12
U13_26 = allwinner.PD11 // LCD-D11
U13_27 = allwinner.PD14 // LCD-D14
U13_28 = allwinner.PD13 // LCD-D13
U13_29 = allwinner.PD18 // LCD-D18
U13_30 = allwinner.PD15 // LCD-D15
U13_31 = allwinner.PD20 // LCD-D20
U13_32 = allwinner.PD19 // LCD-D19
U13_33 = allwinner.PD22 // LCD-D22
U13_34 = allwinner.PD21 // LCD-D21
U13_35 = allwinner.PD24 // LCD-CLK
U13_36 = allwinner.PD23 // LCD-D23
U13_37 = allwinner.PD26 // LCD-VSYNC
U13_38 = allwinner.PD27 // LCD-HSYNC
U13_39 = pin.GROUND //
U13_40 = allwinner.PD25 // LCD-DE: RGB666 data
)
// The U14 header is right next to the power LED.
var (
U14_1 = pin.GROUND //
U14_2 = pin.V5 // (filtered)
U14_3 = allwinner.PG3 // UART1_TX; EINT3
U14_4 = allwinner.HP_LEFT // Headphone left output
U14_5 = allwinner.PG4 // UART1_RX; EINT4
U14_6 = allwinner.HP_COM // Headphone amp out
U14_7 = allwinner.FEL // Boot mode selection
U14_8 = allwinner.HP_RIGHT // Headphone right output
U14_9 = pin.V3_3 //
U14_10 = allwinner.MIC_GND // Microphone ground
U14_11 = allwinner.KEY_ADC // LRADC Low res analog to digital
U14_12 = allwinner.MIC_IN // Microphone input
U14_13 = XIO0 // gpio via I²C controller
U14_14 = XIO1 // gpio via I²C controller
U14_15 = XIO2 // gpio via I²C controller
U14_16 = XIO3 // gpio via I²C controller
U14_17 = XIO4 // gpio via I²C controller
U14_18 = XIO5 // gpio via I²C controller
U14_19 = XIO6 // gpio via I²C controller
U14_20 = XIO7 // gpio via I²C controller
U14_21 = pin.GROUND //
U14_22 = pin.GROUND //
U14_23 = allwinner.PG1 // GPS_CLK; AP-EINT1
U14_24 = allwinner.PB3 // IR_TX; AP-EINT3 (EINT17)
U14_25 = allwinner.PB18 // I2C2_SDA
U14_26 = allwinner.PB17 // I2C2_SCL
U14_27 = allwinner.PE0 // CSIPCK: CMOS serial interface; SPI2_CS0; EINT14
U14_28 = allwinner.PE1 // CSICK: CMOS serial interface; SPI2_CLK; EINT15
U14_29 = allwinner.PE2 // CSIHSYNC; SPI2_MOSI
U14_30 = allwinner.PE3 // CSIVSYNC; SPI2_MISO
U14_31 = allwinner.PE4 // CSID0
U14_32 = allwinner.PE5 // CSID1
U14_33 = allwinner.PE6 // CSID2
U14_34 = allwinner.PE7 // CSID3
U14_35 = allwinner.PE8 // CSID4
U14_36 = allwinner.PE9 // CSID5
U14_37 = allwinner.PE10 // CSID6; UART1_RX
U14_38 = allwinner.PE11 // CSID7; UART1_TX
U14_39 = pin.GROUND //
U14_40 = pin.GROUND //
)
// Present returns true if running on a NextThing Co's C.H.I.P. board.
//
// It looks for "C.H.I.P" in the device tree. The following information is
// expected in the device dtree:
// root@chip2:/proc/device-tree# od -c compatible
// 0000000 n e x t t h i n g , c h i p \0 a
// 0000020 l l w i n n e r , s u n 5 i - r
// 0000040 8 \0
// root@chip2:/proc/device-tree# od -c model
// 0000000 N e x t T h i n g C . H . I .
// 0000020 P . \0
func Present() bool {
return strings.Contains(distro.DTModel(), "C.H.I.P")
}
//
// aliases is a list of aliases for the various gpio pins, this allows users to
// refer to pins using the documented and labeled names instead of some GPIOnnn
// name. The map key is the alias and the value is the real pin name.
var aliases = map[string]string{
"AP-EINT1": "PG1",
"AP-EINT3": "PB3",
"CSIPCK": "PE0",
"CSIHSYNC": "PE2",
"CSID0": "PE4",
"CSID2": "PE6",
"CSID4": "PE8",
"CSID6": "PE10",
"CSICK": "PE1",
"CSIVSYNC": "PE3",
"CSID1": "PE5",
"CSID3": "PE7",
"CSID5": "PE9",
"CSID7": "PE11",
"LCD-CLK": "PD24",
"LCD-D10": "PD10",
"LCD-D11": "PD11",
"LCD-D12": "PD12",
"LCD-D13": "PD13",
"LCD-D14": "PD14",
"LCD-D15": "PD15",
"LCD-D18": "PD18",
"LCD-D19": "PD19",
"LCD-D2": "PD2",
"LCD-D20": "PD20",
"LCD-D21": "PD21",
"LCD-D22": "PD22",
"LCD-D23": "PD23",
"LCD-D3": "PD3",
"LCD-D4": "PD4",
"LCD-D5": "PD5",
"LCD-D6": "PD6",
"LCD-D7": "PD7",
"LCD-DE": "PD25",
"LCD-HSYNC": "PD27",
"LCD-VSYNC": "PD26",
"TWI1-SCK": "PB15",
"TWI1-SDA": "PB16",
"TWI2-SCK": "PB17",
"TWI2-SDA": "PB18",
"UART1-RX": "PG4",
"UART1-TX": "PG3",
}
func init() {
// These are initialized later by the driver.
XIO0 = gpio.INVALID
XIO1 = gpio.INVALID
XIO2 = gpio.INVALID
XIO3 = gpio.INVALID
XIO4 = gpio.INVALID
XIO5 = gpio.INVALID
XIO6 = gpio.INVALID
XIO7 = gpio.INVALID
// These must be reinitialized.
U14_13 = XIO0
U14_14 = XIO1
U14_15 = XIO2
U14_16 = XIO3
U14_17 = XIO4
U14_18 = XIO5
U14_19 = XIO6
U14_20 = XIO7
}
// findXIOBase calculates the base of the XIO-P? gpio pins as explained in
// http://docs.getchip.com/chip.html#kernel-4-3-vs-4-4-gpio-how-to-tell-the-difference
//
// The XIO-P? sysfs mapped pin number changed in kernel 4.3, 4.4.11 and again
// in 4.4.13 so it is better to query sysfs.
func findXIOBase() int {
chips, err := filepath.Glob("/sys/class/gpio/gpiochip*/label")
if err != nil {
return -1
}
for _, item := range chips {
f, err := fs.Open(item, os.O_RDONLY)
if err != nil {
continue
}
b, err := ioutil.ReadAll(f)
if err1 := f.Close(); err == nil {
err = err1
}
if err != nil {
continue
}
if string(b) == "pcf8574a\n" {
id, err := strconv.Atoi(filepath.Base(filepath.Dir(item))[8:])
if err != nil {
return -1
}
return id
}
}
return -1
}
// driver implements drivers.Driver.
type driver struct {
}
func (d *driver) String() string {
return "chip"
}
func (d *driver) Prerequisites() []string {
return nil
}
func (d *driver) After() []string {
// has allwinner cpu, needs sysfs for XIO0-XIO7 "gpio" pins
return []string{"allwinner-gpio", "sysfs-gpio"}
}
func (d *driver) Init() (bool, error) {
if !Present() {
return false, errors.New("NextThing Co. CHIP board not detected")
}
base := findXIOBase()
if base == -1 {
return true, errors.New("couldn't find XIO pins base number")
}
for i := 0; i < 8; i++ {
aliases[fmt.Sprintf("XIO-P%d", i)] = fmt.Sprintf("GPIO%d", base+i)
}
// At this point the sysfs driver has initialized and discovered its pins,
// we can now hook-up the appropriate CHIP pins to sysfs gpio pins.
for alias, real := range aliases {
if err := gpioreg.RegisterAlias(alias, real); err != nil {
return true, err
}
}
// These must be explicitly initialized.
XIO0 = gpioreg.ByName("XIO-P0")
XIO1 = gpioreg.ByName("XIO-P1")
XIO2 = gpioreg.ByName("XIO-P2")
XIO3 = gpioreg.ByName("XIO-P3")
XIO4 = gpioreg.ByName("XIO-P4")
XIO5 = gpioreg.ByName("XIO-P5")
XIO6 = gpioreg.ByName("XIO-P6")
XIO7 = gpioreg.ByName("XIO-P7")
U14_13 = XIO0
U14_14 = XIO1
U14_15 = XIO2
U14_16 = XIO3
U14_17 = XIO4
U14_18 = XIO5
U14_19 = XIO6
U14_20 = XIO7
// U13 is one of the 20x2 connectors.
U13 := [][]pin.Pin{
{U13_1, U13_2},
{U13_3, U13_4},
{U13_5, U13_6},
{U13_7, U13_8},
{gpioreg.ByName("TWI1-SDA"), U13_10},
{gpioreg.ByName("TWI1-SCK"), U13_12},
{U13_13, U13_14},
{U13_15, U13_16},
{gpioreg.ByName("LCD-D2"), gpioreg.ByName("PWM0")},
{gpioreg.ByName("LCD-D4"), gpioreg.ByName("LCD-D3")},
{gpioreg.ByName("LCD-D6"), gpioreg.ByName("LCD-D5")},
{gpioreg.ByName("LCD-D10"), gpioreg.ByName("LCD-D7")},
{gpioreg.ByName("LCD-D12"), gpioreg.ByName("LCD-D11")},
{gpioreg.ByName("LCD-D14"), gpioreg.ByName("LCD-D13")},
{gpioreg.ByName("LCD-D18"), gpioreg.ByName("LCD-D15")},
{gpioreg.ByName("LCD-D20"), gpioreg.ByName("LCD-D19")},
{gpioreg.ByName("LCD-D22"), gpioreg.ByName("LCD-D21")},
{gpioreg.ByName("LCD-CLK"), gpioreg.ByName("LCD-D23")},
{gpioreg.ByName("LCD-VSYNC"), gpioreg.ByName("LCD-HSYNC")},
{U13_39, gpioreg.ByName("LCD-DE")},
}
if err := pinreg.Register("U13", U13); err != nil {
return true, err
}
// U14 is one of the 20x2 connectors.
U14 := [][]pin.Pin{
{U14_1, U14_2},
{gpioreg.ByName("UART1-TX"), U14_4},
{gpioreg.ByName("UART1-RX"), U14_6},
{U14_7, U14_8},
{U14_9, U14_10},
{U14_11, U14_12}, // TODO(maruel): switch to LRADC once analog support is added
{U14_13, U14_14},
{U14_15, U14_16},
{U14_17, U14_18},
{U14_19, U14_20},
{U14_21, U14_22},
{gpioreg.ByName("AP-EINT1"), gpioreg.ByName("AP-EINT3")},
{gpioreg.ByName("TWI2-SDA"), gpioreg.ByName("TWI2-SCK")},
{gpioreg.ByName("CSIPCK"), gpioreg.ByName("CSICK")},
{gpioreg.ByName("CSIHSYNC"), gpioreg.ByName("CSIVSYNC")},
{gpioreg.ByName("CSID0"), gpioreg.ByName("CSID1")},
{gpioreg.ByName("CSID2"), gpioreg.ByName("CSID3")},
{gpioreg.ByName("CSID4"), gpioreg.ByName("CSID5")},
{gpioreg.ByName("CSID6"), gpioreg.ByName("CSID7")},
{U14_39, U14_40},
}
return true, pinreg.Register("U14", U14)
}
func init() {
if isArm {
periph.MustRegister(&drv)
}
}
var drv driver

7
vendor/periph.io/x/periph/host/chip/chip_arm.go generated vendored Normal file
View File

@ -0,0 +1,7 @@
// 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 chip
const isArm = true

9
vendor/periph.io/x/periph/host/chip/chip_other.go generated vendored Normal file
View File

@ -0,0 +1,9 @@
// 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.
// +build !arm
package chip
const isArm = false

30
vendor/periph.io/x/periph/host/chip/doc.go generated vendored Normal file
View File

@ -0,0 +1,30 @@
// 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 chip contains header definitions for NextThing Co's C.H.I.P. board.
//
// CHIP uses the Allwinner R8 processor and thus the allwinner host package is
// automatically imported.
//
// This package exports the U13 header, which is opposite the power LED, and
// U14, which is right next to the power LED. Most of the pins are usable as
// GPIO and are directly to the processor. These can use memory-mapped GPIO,
// which is very fast. The XIO-P0 through XIO-P7 pins are attached to a pcf8574
// I²C expander which has the result that all accesses to these pins have to go
// through the kernel and the I²C bus protocol, i.e., they're slow.
//
// GPIO edge detection (using interrupts) is only supported on a few of the
// processor's pins: AP-EINT1, AP-EINT3, CSIPCK, and CSICK. Edge detection is
// also supported on the XIO pins, but this feature is rather limited due to
// the device and the driver (for example, the driver interrupts on all edges).
//
// References
//
// http://www.chip-community.org/index.php/Hardware_Information
//
// http://docs.getchip.com/chip.html#chip-hardware
//
// A graphical view of the board headers is available at:
// http://docs.getchip.com/chip.html#pin-headers
package chip

83
vendor/periph.io/x/periph/host/cpu/cpu.go generated vendored Normal file
View File

@ -0,0 +1,83 @@
// 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 cpu
import (
"io"
"io/ioutil"
"os"
"strconv"
"strings"
"sync"
"time"
"periph.io/x/periph/host/fs"
)
// MaxSpeed returns the processor maximum speed in Hz.
//
// Returns 0 if it couldn't be calculated.
func MaxSpeed() int64 {
if isLinux {
return getMaxSpeedLinux()
}
return 0
}
// Nanospin spins for a short amount of time doing a busy loop.
//
// This function should be called with durations of 10µs or less.
func Nanospin(d time.Duration) {
// TODO(maruel): Use runtime.LockOSThread()?
if isLinux {
nanospinLinux(d)
} else {
nanospinTime(d)
}
}
//
var (
mu sync.Mutex
maxSpeed int64 = -1
openFile = openFileOrig
)
func openFileOrig(path string, flag int) (io.ReadCloser, error) {
f, err := fs.Open(path, flag)
if err != nil {
return nil, err
}
return f, nil
}
func getMaxSpeedLinux() int64 {
mu.Lock()
defer mu.Unlock()
if maxSpeed == -1 {
maxSpeed = 0
if f, err := openFile("/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq", os.O_RDONLY); err == nil {
defer f.Close()
if b, err := ioutil.ReadAll(f); err == nil {
s := strings.TrimSpace(string(b))
if i, err := strconv.ParseInt(s, 10, 64); err == nil {
// Weirdly, the speed is listed as khz. :(
maxSpeed = i * 1000
}
}
}
}
return maxSpeed
}
func nanospinTime(d time.Duration) {
// TODO(maruel): That's not optimal; it's actually pretty bad.
// time.Sleep() sleeps for really too long, calling it repeatedly with
// minimal value will give the caller a wake rate of 5KHz or so, depending on
// the host. This makes it useless for bitbanging protocol implementations.
for start := time.Now(); time.Since(start) < d; {
}
}

22
vendor/periph.io/x/periph/host/cpu/cpu_linux.go generated vendored Normal file
View File

@ -0,0 +1,22 @@
// 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 cpu
import (
"syscall"
"time"
)
const isLinux = true
func nanospinLinux(d time.Duration) {
// runtime.nanotime() is not exported so it cannot be used to busy loop for
// very short sleep (10µs or less).
time := syscall.NsecToTimespec(d.Nanoseconds())
leftover := syscall.Timespec{}
for syscall.Nanosleep(&time, &leftover) != nil {
time = leftover
}
}

14
vendor/periph.io/x/periph/host/cpu/cpu_other.go generated vendored Normal file
View File

@ -0,0 +1,14 @@
// 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.
// +build !linux
package cpu
import "time"
const isLinux = false
func nanospinLinux(d time.Duration) {
}

6
vendor/periph.io/x/periph/host/cpu/doc.go generated vendored Normal file
View File

@ -0,0 +1,6 @@
// 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 cpu implements functions relating to the host CPU itself.
package cpu

61
vendor/periph.io/x/periph/host/distro/devtree.go generated vendored Normal file
View File

@ -0,0 +1,61 @@
// 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 distro
// DTModel returns platform model info from the Linux device tree (/proc/device-tree/model), and
// returns "unknown" on non-linux systems or if the file is missing.
func DTModel() string {
mu.Lock()
defer mu.Unlock()
if dtModel == "" {
dtModel = "<unknown>"
if isLinux {
dtModel = makeDTModelLinux()
}
}
return dtModel
}
// DTCompatible returns platform compatibility info from the Linux device tree
// (/proc/device-tree/compatible), and returns []{"unknown"} on non-linux systems or if the file is
// missing.
func DTCompatible() []string {
mu.Lock()
defer mu.Unlock()
if dtCompatible == nil {
dtCompatible = []string{}
if isLinux {
dtCompatible = makeDTCompatible()
}
}
return dtCompatible
}
//
var (
dtModel string // cached /proc/device-tree/model
dtCompatible []string // cached /proc/device-tree/compatible
)
func makeDTModelLinux() string {
// Read model from device tree.
if bytes, err := readFile("/proc/device-tree/model"); err == nil {
if model := splitNull(bytes); len(model) > 0 {
return model[0]
}
}
return "<unknown>"
}
func makeDTCompatible() []string {
// Read compatible from device tree.
if bytes, err := readFile("/proc/device-tree/compatible"); err == nil {
return splitNull(bytes)
}
return []string{}
}

189
vendor/periph.io/x/periph/host/distro/distro.go generated vendored Normal file
View File

@ -0,0 +1,189 @@
// 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 distro implements common functionality to auto-detect features on
// the host; generally about linux distributions.
//
// Most of the functions exported as in the form IsFoo() where Foo is a linux
// distribution.
package distro
import (
"io/ioutil"
"os"
"strconv"
"strings"
"sync"
"unicode"
)
// IsArmbian returns true if running on a Armbian distribution.
//
// http://www.armbian.com/
func IsArmbian() bool {
if isArm && isLinux {
// Armbian presents itself as debian in /etc/os-release so OSRelease()
// cannot be used..
_, err := os.Stat("/etc/armbian.txt")
return err == nil
}
return false
}
// IsDebian returns true if running on an Debian derived distribution.
//
// This function returns true on both Armbian, Raspbian and Ubuntu.
//
// https://debian.org/
func IsDebian() bool {
if isLinux {
// http://0pointer.de/public/systemd-man/os-release.html#ID_LIKE=
if OSRelease()["ID"] == "debian" {
return true
}
for _, part := range strings.Split(OSRelease()["ID_LIKE"], " ") {
if part == "debian" {
return true
}
}
}
return false
}
// IsRaspbian returns true if running on a Raspbian distribution.
//
// https://raspbian.org/
func IsRaspbian() bool {
if isArm && isLinux {
return OSRelease()["ID"] == "raspbian"
}
return false
}
// IsUbuntu returns true if running on an Ubuntu derived distribution.
//
// https://ubuntu.com/
func IsUbuntu() bool {
if isLinux {
return OSRelease()["ID"] == "ubuntu"
}
return false
}
// OSRelease returns parsed data from /etc/os-release.
//
// For more information, see
// http://0pointer.de/public/systemd-man/os-release.html
func OSRelease() map[string]string {
if isLinux {
return makeOSReleaseLinux()
}
return osRelease
}
// CPU
// CPUInfo returns parsed data from /proc/cpuinfo.
func CPUInfo() map[string]string {
if isLinux {
return makeCPUInfoLinux()
}
return cpuInfo
}
//
var (
mu sync.Mutex
cpuInfo map[string]string
osRelease map[string]string
readFile = ioutil.ReadFile
)
func splitSemiColon(content string) map[string]string {
// Strictly speaking this format isn't ok, there can be multiple group.
out := map[string]string{}
for _, line := range strings.Split(content, "\n") {
parts := strings.SplitN(line, ":", 2)
if len(parts) != 2 {
continue
}
// This format may have space around the ':'.
key := strings.TrimRightFunc(parts[0], unicode.IsSpace)
if len(key) == 0 || key[0] == '#' {
continue
}
// Ignore duplicate keys.
// TODO(maruel): Keep them all.
if _, ok := out[key]; !ok {
// Trim on both side, trailing space was observed on "Features" value.
out[key] = strings.TrimFunc(parts[1], unicode.IsSpace)
}
}
return out
}
func splitStrict(content string) map[string]string {
out := map[string]string{}
for _, line := range strings.Split(content, "\n") {
parts := strings.SplitN(line, "=", 2)
if len(parts) != 2 {
continue
}
key := parts[0]
if len(key) == 0 || key[0] == '#' {
continue
}
// Overwrite previous key.
value := parts[1]
if len(value) > 2 && value[0] == '"' && value[len(value)-1] == '"' {
// Not exactly 100% right but #closeenough. See for more details
// https://www.freedesktop.org/software/systemd/man/os-release.html
var err error
value, err = strconv.Unquote(value)
if err != nil {
continue
}
}
out[key] = value
}
return out
}
// splitNull returns the null-terminated strings in the data
func splitNull(data []byte) []string {
ss := strings.Split(string(data), "\x00")
// The last string is typically null-terminated, so remove empty string
// from end of array.
if len(ss) > 0 && len(ss[len(ss)-1]) == 0 {
ss = ss[:len(ss)-1]
}
return ss
}
func makeCPUInfoLinux() map[string]string {
mu.Lock()
defer mu.Unlock()
if cpuInfo == nil {
cpuInfo = map[string]string{}
if bytes, err := readFile("/proc/cpuinfo"); err == nil {
cpuInfo = splitSemiColon(string(bytes))
}
}
return cpuInfo
}
func makeOSReleaseLinux() map[string]string {
mu.Lock()
defer mu.Unlock()
if osRelease == nil {
// This file may not exist on older distros. Send a PR if you want to have
// a specific fallback.
osRelease = map[string]string{}
if bytes, err := readFile("/etc/os-release"); err == nil {
osRelease = splitStrict(string(bytes))
}
}
return osRelease
}

7
vendor/periph.io/x/periph/host/distro/distro_arm.go generated vendored Normal file
View File

@ -0,0 +1,7 @@
// 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 distro
const isArm = true

View File

@ -0,0 +1,9 @@
// 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.
// +build arm64
package distro
const isArm = true

View File

@ -0,0 +1,7 @@
// 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 distro
const isLinux = true

View File

@ -0,0 +1,9 @@
// 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.
// +build !arm,!arm64
package distro
const isArm = false

View File

@ -0,0 +1,9 @@
// 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.
// +build !linux
package distro
const isLinux = false

10
vendor/periph.io/x/periph/host/doc.go generated vendored Normal file
View File

@ -0,0 +1,10 @@
// 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 host defines the host itself.
//
// The host is the machine where this code is running.
//
// Subpackages contain the drivers that are loaded automatically.
package host

100
vendor/periph.io/x/periph/host/fs/fs.go generated vendored Normal file
View File

@ -0,0 +1,100 @@
// 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.
// Package fs provides access to the file system on the host.
//
// It exposes ioctl syscall and epoll in an OS agnostic way and permits
// completely disabling file access to lock down unit tests.
package fs
import (
"errors"
"os"
"sync"
)
// Ioctler is a file handle that supports ioctl calls.
type Ioctler interface {
// Ioctl sends a linux ioctl on the file handle.
//
// op is effectively an uint32. op is expected to be encoded in the format on
// x64. ARM happens to share the same format.
Ioctl(op uint, data uintptr) error
}
// Open opens a file.
//
// Returns an error if Inhibit() was called.
func Open(path string, flag int) (*File, error) {
mu.Lock()
if inhibited {
mu.Unlock()
return nil, errors.New("file I/O is inhibited")
}
used = true
mu.Unlock()
f, err := os.OpenFile(path, flag, 0600)
if err != nil {
return nil, err
}
return &File{f}, nil
}
// Inhibit inhibits any future file I/O. It panics if any file was opened up to
// now.
//
// It should only be called in unit tests.
func Inhibit() {
mu.Lock()
inhibited = true
if used {
panic("calling Inhibit() while files were already opened")
}
mu.Unlock()
}
// File is a superset of os.File.
type File struct {
*os.File
}
// Ioctl sends an ioctl to the file handle.
func (f *File) Ioctl(op uint, data uintptr) error {
return ioctl(f.Fd(), op, data)
}
// Event is a file system event.
type Event struct {
event
}
// MakeEvent initializes an epoll *edge* triggered event on linux.
//
// An edge triggered event is basically an "auto-reset" event, where waiting on
// the edge resets it. A level triggered event requires manual resetting; this
// could be done via a Read() call but there's no need to require the user to
// call Read(). This is particularly useless in the case of gpio.RisingEdge and
// gpio.FallingEdge.
//
// As per the official doc, edge triggers is still remembered even when no
// epoll_wait() call is running, so no edge is missed. Two edges will be
// coallesced into one if the user mode process can't keep up. There's no
// accumulation of edges.
func (e *Event) MakeEvent(fd uintptr) error {
return e.event.makeEvent(fd)
}
// Wait waits for an event or the specified amount of time.
func (e *Event) Wait(timeoutms int) (int, error) {
return e.event.wait(timeoutms)
}
//
var (
mu sync.Mutex
inhibited bool
used bool
)

124
vendor/periph.io/x/periph/host/fs/fs_linux.go generated vendored Normal file
View File

@ -0,0 +1,124 @@
// 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.
package fs
import (
"strconv"
"strings"
"syscall"
)
const isLinux = true
// syscall.EpollCtl() commands.
//
// These are defined here so we don't need to import golang.org/x/sys/unix.
//
// http://man7.org/linux/man-pages/man2/epoll_ctl.2.html
const (
epollCTLAdd = 1 // EPOLL_CTL_ADD
epollCTLDel = 2 // EPOLL_CTL_DEL
epollCTLMod = 3 // EPOLL_CTL_MOD
)
// Bitmask for field syscall.EpollEvent.Events.
//
// These are defined here so we don't need to import golang.org/x/sys/unix.
//
// http://man7.org/linux/man-pages/man2/epoll_ctl.2.html
type epollEvent uint32
const (
epollIN epollEvent = 0x1 // EPOLLIN: available for read
epollOUT epollEvent = 0x4 // EPOLLOUT: available for write
epollPRI epollEvent = 0x2 // EPOLLPRI: exceptional urgent condition
epollERR epollEvent = 0x8 // EPOLLERR: error
epollHUP epollEvent = 0x10 // EPOLLHUP: hangup
epollET epollEvent = 0x80000000 // EPOLLET: Edge Triggered behavior
epollONESHOT epollEvent = 0x40000000 // EPOLLONESHOT: One shot
epollWAKEUP epollEvent = 0x20000000 // EPOLLWAKEUP: disable system sleep; kernel >=3.5
epollEXCLUSIVE epollEvent = 0x10000000 // EPOLLEXCLUSIVE: only wake one; kernel >=4.5
)
var bitmaskString = [...]struct {
e epollEvent
s string
}{
{epollIN, "IN"},
{epollOUT, "OUT"},
{epollPRI, "PRI"},
{epollERR, "ERR"},
{epollHUP, "HUP"},
{epollET, "ET"},
{epollONESHOT, "ONESHOT"},
{epollWAKEUP, "WAKEUP"},
{epollEXCLUSIVE, "EXCLUSIVE"},
}
// String is useful for debugging.
func (e epollEvent) String() string {
var out []string
for _, b := range bitmaskString {
if e&b.e != 0 {
out = append(out, b.s)
e &^= b.e
}
}
if e != 0 {
out = append(out, "0x"+strconv.FormatUint(uint64(e), 16))
}
if len(out) == 0 {
out = []string{"0"}
}
return strings.Join(out, "|")
}
func ioctl(f uintptr, op uint, arg uintptr) error {
if _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, f, uintptr(op), arg); errno != 0 {
return syscall.Errno(errno)
}
return nil
}
type event struct {
event [1]syscall.EpollEvent
epollFd int
fd int
}
// makeEvent creates an epoll *edge* triggered event.
//
// References:
// behavior and flags: http://man7.org/linux/man-pages/man7/epoll.7.html
// syscall.EpollCreate: http://man7.org/linux/man-pages/man2/epoll_create.2.html
// syscall.EpollCtl: http://man7.org/linux/man-pages/man2/epoll_ctl.2.html
func (e *event) makeEvent(fd uintptr) error {
epollFd, err := syscall.EpollCreate(1)
switch {
case err == nil:
break
case err.Error() == "function not implemented":
// Some arch (arm64) do not implement EpollCreate().
if epollFd, err = syscall.EpollCreate1(0); err != nil {
return err
}
default:
return err
}
e.epollFd = epollFd
e.fd = int(fd)
// EPOLLWAKEUP could be used to force the system to not go do sleep while
// waiting for an edge. This is generally a bad idea, as we'd instead have
// the system to *wake up* when an edge is triggered. Achieving this is
// outside the scope of this interface.
e.event[0].Events = uint32(epollPRI | epollET)
e.event[0].Fd = int32(e.fd)
return syscall.EpollCtl(e.epollFd, epollCTLAdd, e.fd, &e.event[0])
}
func (e *event) wait(timeoutms int) (int, error) {
// http://man7.org/linux/man-pages/man2/epoll_wait.2.html
return syscall.EpollWait(e.epollFd, e.event[:], timeoutms)
}

25
vendor/periph.io/x/periph/host/fs/fs_other.go generated vendored Normal file
View File

@ -0,0 +1,25 @@
// 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.
// +build !linux
package fs
import "errors"
const isLinux = false
func ioctl(f uintptr, op uint, arg uintptr) error {
return errors.New("fs: ioctl not supported on non-linux")
}
type event struct{}
func (e *event) makeEvent(f uintptr) error {
return errors.New("fs: unreachable code")
}
func (e *event) wait(timeoutms int) (int, error) {
return 0, errors.New("fs: unreachable code")
}

51
vendor/periph.io/x/periph/host/fs/ioctl.go generated vendored Normal file
View File

@ -0,0 +1,51 @@
// Copyright 2019 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 fs
// These constants, variables and functions are ported from the Linux userland
// API header ioctl.h (commonly packaged at /usr/include/linux/ioctl.h which
// includes /usr/include/asm-generic/ioctl.h).
const (
iocNrbits uint = 8
iocTypebits uint = 8
iocNrshift uint = 0
iocTypeshift = iocNrshift + iocNrbits
iocSizeshift = iocTypeshift + iocTypebits
iocDirshift = iocSizeshift + iocSizebits
)
func ioc(dir, typ, nr, size uint) uint {
return (dir << iocDirshift) |
(typ << iocTypeshift) |
(nr << iocNrshift) |
(size << iocSizeshift)
}
// IO defines an ioctl with no parameters. It corresponds to _IO in the Linux
// userland API.
func IO(typ, nr uint) uint {
return ioc(iocNone, typ, nr, 0)
}
// IOR defines an ioctl with read (userland perspective) parameters. It
// corresponds to _IOR in the Linux userland API.
func IOR(typ, nr, size uint) uint {
return ioc(iocRead, typ, nr, size)
}
// IOW defines an ioctl with write (userland perspective) parameters. It
// corresponds to _IOW in the Linux userland API.
func IOW(typ, nr, size uint) uint {
return ioc(iocWrite, typ, nr, size)
}
// IOWR defines an ioctl with both read and write parameters. It corresponds to
// _IOWR in the Linux userland API.
func IOWR(typ, nr, size uint) uint {
return ioc(iocRead|iocWrite, typ, nr, size)
}

16
vendor/periph.io/x/periph/host/fs/ioctl_mips_like.go generated vendored Normal file
View File

@ -0,0 +1,16 @@
// Copyright 2018 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.
// +build mips mipsle
package fs
const (
iocNone uint = 1
iocRead uint = 2
iocWrite uint = 4
iocSizebits uint = 13
iocDirbits uint = 3
)

16
vendor/periph.io/x/periph/host/fs/ioctl_other.go generated vendored Normal file
View File

@ -0,0 +1,16 @@
// Copyright 2018 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.
// +build !mips,!mipsle
package fs
const (
iocNone uint = 0
iocWrite uint = 1
iocRead uint = 2
iocSizebits uint = 14
iocDirbits uint = 2
)

15
vendor/periph.io/x/periph/host/host.go generated vendored Normal file
View File

@ -0,0 +1,15 @@
// 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 host
import "periph.io/x/periph"
// Init calls periph.Init() and returns it as-is.
//
// The only difference is that by calling host.Init(), you are guaranteed to
// have all the drivers implemented in this library to be implicitly loaded.
func Init() (*periph.State, error) {
return periph.Init()
}

20
vendor/periph.io/x/periph/host/host_arm.go generated vendored Normal file
View File

@ -0,0 +1,20 @@
// 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 host
import (
// Make sure CPU and board drivers are registered.
_ "periph.io/x/periph/host/allwinner"
_ "periph.io/x/periph/host/am335x"
_ "periph.io/x/periph/host/bcm283x"
_ "periph.io/x/periph/host/beagle/bone"
_ "periph.io/x/periph/host/beagle/green"
_ "periph.io/x/periph/host/chip"
_ "periph.io/x/periph/host/odroidc1"
// While this board is ARM64, it may run ARM 32 bits binaries so load it on
// 32 bits builds too.
_ "periph.io/x/periph/host/pine64"
_ "periph.io/x/periph/host/rpi"
)

13
vendor/periph.io/x/periph/host/host_arm64.go generated vendored Normal file
View File

@ -0,0 +1,13 @@
// 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 host
import (
// Make sure CPU and board drivers are registered.
_ "periph.io/x/periph/host/allwinner"
_ "periph.io/x/periph/host/bcm283x"
_ "periph.io/x/periph/host/pine64"
_ "periph.io/x/periph/host/rpi"
)

10
vendor/periph.io/x/periph/host/host_linux.go generated vendored Normal file
View File

@ -0,0 +1,10 @@
// 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 host
import (
// Make sure sysfs drivers are registered.
_ "periph.io/x/periph/host/sysfs"
)

26
vendor/periph.io/x/periph/host/odroidc1/doc.go generated vendored Normal file
View File

@ -0,0 +1,26 @@
// 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 odroidc1 contains header definitions for Hardkernel's ODROID C0, C1,
// and C1+ boards.
//
// These boards use an Amlogic S805 processor (called "meson_8b" in the linux
// kernel). Currently no package for memory-mapped I/O has been written for
// this processor, thus all gpio functions are implemented via sysfs.
//
// This package only exports the main J2 header, which is rPi compatible except
// for a couple of analog pins (which are not currently supported). The J2
// header has two I²C buses on header pins 3/5 and 27/28, the I²C functionality
// can be enabled by loading the aml_i2c kernel module. It has one SPI bus on
// header pins 19/21/23/24. The onewire gpio driver appears to be loaded by
// default on header pin 7.
//
// References
//
// Product page: http://www.hardkernel.com/main/products/prdt_info.php?g_code=G143703355573&tab_idx=2
//
// Hardware wiki: http://odroid.com/dokuwiki/doku.php?id=en:c1_hardware
//
// Ubuntu drivers: http://odroid.com/dokuwiki/doku.php?id=en:odroid-c1#ubuntu
package odroidc1

195
vendor/periph.io/x/periph/host/odroidc1/odroidc1.go generated vendored Normal file
View File

@ -0,0 +1,195 @@
// 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 odroidc1
import (
"errors"
"strconv"
"strings"
"periph.io/x/periph"
"periph.io/x/periph/conn/gpio"
"periph.io/x/periph/conn/gpio/gpioreg"
"periph.io/x/periph/conn/pin"
"periph.io/x/periph/conn/pin/pinreg"
"periph.io/x/periph/host/distro"
"periph.io/x/periph/host/sysfs"
)
// The J2 header is rPi compatible, except for the two analog pins and the 1.8V
// output.
var (
J2_1 = pin.V3_3 // 3.3V; max 30mA
J2_2 = pin.V5 // 5V (after filtering)
J2_3 gpio.PinIO = gpio.INVALID // I2C1_SDA
J2_4 = pin.V5 // 5V (after filtering)
J2_5 gpio.PinIO = gpio.INVALID // I2C1_SCL
J2_6 = pin.GROUND //
J2_7 gpio.PinIO = gpio.INVALID // CLK0
J2_8 gpio.PinIO = gpio.INVALID // UART0_TX, UART1_TX
J2_9 = pin.GROUND //
J2_10 gpio.PinIO = gpio.INVALID // UART0_RX, UART1_RX
J2_11 gpio.PinIO = gpio.INVALID // UART0_RTS, SPI1_CS1, UART1_RTS
J2_12 gpio.PinIO = gpio.INVALID // I2S_SCK, SPI1_CS0, PWM0
J2_13 gpio.PinIO = gpio.INVALID // GPIO116
J2_14 = pin.GROUND //
J2_15 gpio.PinIO = gpio.INVALID // GPIO115
J2_16 gpio.PinIO = gpio.INVALID // GPIO104
J2_17 = pin.V3_3 //
J2_18 gpio.PinIO = gpio.INVALID // GPIO102
J2_19 gpio.PinIO = gpio.INVALID // SPI0_MOSI
J2_20 = pin.GROUND //
J2_21 gpio.PinIO = gpio.INVALID // SPI0_MISO
J2_22 gpio.PinIO = gpio.INVALID // GPIO103
J2_23 gpio.PinIO = gpio.INVALID // SPI0_CLK
J2_24 gpio.PinIO = gpio.INVALID // SPI0_CS0
J2_25 = pin.GROUND //
J2_26 gpio.PinIO = gpio.INVALID // SPI0_CS1
J2_27 gpio.PinIO = gpio.INVALID // I2C0_SDA
J2_28 gpio.PinIO = gpio.INVALID // I2C0_SCL
J2_29 gpio.PinIO = gpio.INVALID // CLK1
J2_30 = pin.GROUND //
J2_31 gpio.PinIO = gpio.INVALID // CLK2
J2_32 gpio.PinIO = gpio.INVALID // PWM0
J2_33 gpio.PinIO = gpio.INVALID // PWM1
J2_34 = pin.GROUND //
J2_35 gpio.PinIO = gpio.INVALID // I2S_WS, SPI1_MISO, PWM1
J2_36 gpio.PinIO = gpio.INVALID // UART0_CTS, SPI1_CS2, UART1_CTS
J2_37 = pin.INVALID // BUG(tve): make pins J2_37 and J2_40 functional once analog support is implemented
J2_38 = pin.V1_8 //
J2_39 = pin.GROUND //
J2_40 = pin.INVALID // See above.
)
// Present returns true if running on a Hardkernel ODROID-C0/C1/C1+ board.
//
// It looks for "8726_M8B" in the device tree or "ODROIDC" in cpuinfo. The
// following information is expected in the device dtree:
// root@odroid:/proc/device-tree# od -c compatible
// 0000000 A M L O G I C , 8 7 2 6 _ M 8 B
func Present() bool {
for _, c := range distro.DTCompatible() {
if strings.Contains(c, "8726_M8B") {
return true
}
}
return distro.CPUInfo()["Hardware"] == "ODROIDC"
}
//
// aliases is a list of aliases for the various gpio pins, this allows users to
// refer to pins using the documented and labeled names instead of some GPIOnnn
// name. The map key is the alias and the value is the real pin name.
var aliases = map[string]int{
"I2C0_SDA": 74,
"I2C0_SCL": 75,
"I2C1_SDA": 76,
"I2C1_SCL": 77,
"I2CA_SDA": 74,
"I2CA_SCL": 75,
"I2CB_SDA": 76,
"I2CB_SCL": 77,
"SPI0_MOSI": 107,
"SPI0_MISO": 106,
"SPI0_CLK": 105,
"SPI0_CS0": 117,
}
// sysfsPin is a safe way to get a sysfs pin
func sysfsPin(n int) gpio.PinIO {
if p, ok := sysfs.Pins[n]; ok {
return p
}
return gpio.INVALID
}
// driver implements drivers.Driver.
type driver struct {
}
func (d *driver) String() string {
return "odroid-c1"
}
func (d *driver) Prerequisites() []string {
return nil
}
func (d *driver) After() []string {
return []string{"sysfs-gpio"}
}
func (d *driver) Init() (bool, error) {
if !Present() {
return false, errors.New("Hardkernel ODROID-C0/C1/C1+ board not detected")
}
J2_3 = sysfsPin(74)
J2_5 = sysfsPin(75)
J2_7 = sysfsPin(83) // usually taken by 1-wire driver
J2_8 = sysfsPin(113) // usually not available
J2_10 = sysfsPin(114) // usually not available
J2_11 = sysfsPin(88)
J2_12 = sysfsPin(87)
J2_13 = sysfsPin(116)
J2_15 = sysfsPin(115)
J2_16 = sysfsPin(104)
J2_18 = sysfsPin(102)
J2_19 = sysfsPin(107)
J2_21 = sysfsPin(106)
J2_22 = sysfsPin(103)
J2_23 = sysfsPin(105)
J2_24 = sysfsPin(117)
J2_26 = sysfsPin(118)
J2_27 = sysfsPin(76)
J2_28 = sysfsPin(77)
J2_29 = sysfsPin(101)
J2_31 = sysfsPin(100)
J2_32 = sysfsPin(99)
J2_33 = sysfsPin(108)
J2_35 = sysfsPin(97)
J2_36 = sysfsPin(98)
// J2 is the 40-pin rPi-compatible header
J2 := [][]pin.Pin{
{J2_1, J2_2},
{J2_3, J2_4},
{J2_5, J2_6},
{J2_7, J2_8},
{J2_9, J2_10},
{J2_11, J2_12},
{J2_13, J2_14},
{J2_15, J2_16},
{J2_17, J2_18},
{J2_19, J2_20},
{J2_21, J2_22},
{J2_23, J2_24},
{J2_25, J2_26},
{J2_27, J2_28},
{J2_29, J2_30},
{J2_31, J2_32},
{J2_33, J2_34},
{J2_35, J2_36},
{J2_37, J2_38},
{J2_39, J2_40},
}
if err := pinreg.Register("J2", J2); err != nil {
return true, err
}
for alias, number := range aliases {
if err := gpioreg.RegisterAlias(alias, strconv.Itoa(number)); err != nil {
return true, err
}
}
return true, nil
}
func init() {
if isArm {
periph.MustRegister(&drv)
}
}
var drv driver

View File

@ -0,0 +1,7 @@
// Copyright 2016 The PIO 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 odroidc1
const isArm = true

View File

@ -0,0 +1,9 @@
// Copyright 2016 The PIO 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.
// +build !arm
package odroidc1
const isArm = false

15
vendor/periph.io/x/periph/host/pine64/doc.go generated vendored Normal file
View File

@ -0,0 +1,15 @@
// 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 pine64 contains Pine64 hardware logic. It is intrinsically
// related to package a64.
//
// Requires Armbian Jessie Server.
//
// Physical
//
// http://files.pine64.org/doc/Pine%20A64%20Schematic/Pine%20A64%20Pin%20Assignment%20160119.pdf
//
// http://wiki.pine64.org/images/2/2e/Pine64_Board_Connector_heatsink.png
package pine64

272
vendor/periph.io/x/periph/host/pine64/pine64.go generated vendored Normal file
View File

@ -0,0 +1,272 @@
// 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 pine64
import (
"errors"
"os"
"periph.io/x/periph"
"periph.io/x/periph/conn/pin"
"periph.io/x/periph/conn/pin/pinreg"
"periph.io/x/periph/host/allwinner"
)
// Present returns true if running on a Pine64 board.
//
// https://www.pine64.org/
func Present() bool {
if isArm {
// This is iffy at best.
_, err := os.Stat("/boot/pine64.dtb")
return err == nil
}
return false
}
// Pine64 specific pins.
var (
VCC = &pin.BasicPin{N: "VCC"} //
IOVCC = &pin.BasicPin{N: "IOVCC"} // Power supply for port A
TEMP_SENSOR = &pin.BasicPin{N: "TEMP_SENSOR"} //
IR_RX = &pin.BasicPin{N: "IR_RX"} // IR Data Receive
CHARGER_LED = &pin.BasicPin{N: "CHARGER_LED"} //
RESET = &pin.BasicPin{N: "RESET"} //
PWR_SWITCH = &pin.BasicPin{N: "PWR_SWITCH "} //
)
// All the individual pins on the headers.
var (
P1_1 = pin.V3_3 // max 40mA
P1_2 = pin.V5 // (filtered)
P1_3 = allwinner.PH3 //
P1_4 = pin.V5 // (filtered)
P1_5 = allwinner.PH2 //
P1_6 = pin.GROUND //
P1_7 = allwinner.PL10 //
P1_8 = allwinner.PB0 //
P1_9 = pin.GROUND //
P1_10 = allwinner.PB1 //
P1_11 = allwinner.PC7 //
P1_12 = allwinner.PC8 //
P1_13 = allwinner.PH9 //
P1_14 = pin.GROUND //
P1_15 = allwinner.PC12 //
P1_16 = allwinner.PC13 //
P1_17 = pin.V3_3 //
P1_18 = allwinner.PC14 //
P1_19 = allwinner.PC0 //
P1_20 = pin.GROUND //
P1_21 = allwinner.PC1 //
P1_22 = allwinner.PC15 //
P1_23 = allwinner.PC2 //
P1_24 = allwinner.PC3 //
P1_25 = pin.GROUND //
P1_26 = allwinner.PH7 //
P1_27 = allwinner.PL9 //
P1_28 = allwinner.PL8 //
P1_29 = allwinner.PH5 //
P1_30 = pin.GROUND //
P1_31 = allwinner.PH6 //
P1_32 = allwinner.PC4 //
P1_33 = allwinner.PC5 //
P1_34 = pin.GROUND //
P1_35 = allwinner.PC9 //
P1_36 = allwinner.PC6 //
P1_37 = allwinner.PC16 //
P1_38 = allwinner.PC10 //
P1_39 = pin.GROUND //
P1_40 = allwinner.PC11 //
EULER_1 = pin.V3_3 //
EULER_2 = pin.DC_IN //
EULER_3 = pin.BAT_PLUS //
EULER_4 = pin.DC_IN //
EULER_5 = TEMP_SENSOR //
EULER_6 = pin.GROUND //
EULER_7 = IR_RX //
EULER_8 = pin.V5 //
EULER_9 = pin.GROUND //
EULER_10 = allwinner.PH8 //
EULER_11 = allwinner.PB3 //
EULER_12 = allwinner.PB4 //
EULER_13 = allwinner.PB5 //
EULER_14 = pin.GROUND //
EULER_15 = allwinner.PB6 //
EULER_16 = allwinner.PB7 //
EULER_17 = pin.V3_3 //
EULER_18 = allwinner.PD4 //
EULER_19 = allwinner.PD2 //
EULER_20 = pin.GROUND //
EULER_21 = allwinner.PD3 //
EULER_22 = allwinner.PD5 //
EULER_23 = allwinner.PD1 //
EULER_24 = allwinner.PD0 //
EULER_25 = pin.GROUND //
EULER_26 = allwinner.PD6 //
EULER_27 = allwinner.PB2 //
EULER_28 = allwinner.PD7 //
EULER_29 = allwinner.PB8 //
EULER_30 = allwinner.PB9 //
EULER_31 = allwinner.EAROUTP //
EULER_32 = allwinner.EAROUTN //
EULER_33 = pin.INVALID //
EULER_34 = pin.GROUND //
EXP_1 = pin.V3_3 //
EXP_2 = allwinner.PL7 //
EXP_3 = CHARGER_LED //
EXP_4 = RESET //
EXP_5 = PWR_SWITCH //
EXP_6 = pin.GROUND //
EXP_7 = allwinner.PB8 //
EXP_8 = allwinner.PB9 //
EXP_9 = pin.GROUND //
EXP_10 = allwinner.KEY_ADC //
WIFI_BT_1 = pin.GROUND //
WIFI_BT_2 = allwinner.PG6 //
WIFI_BT_3 = allwinner.PG0 //
WIFI_BT_4 = allwinner.PG7 //
WIFI_BT_5 = pin.GROUND //
WIFI_BT_6 = allwinner.PG8 //
WIFI_BT_7 = allwinner.PG1 //
WIFI_BT_8 = allwinner.PG9 //
WIFI_BT_9 = allwinner.PG2 //
WIFI_BT_10 = allwinner.PG10 //
WIFI_BT_11 = allwinner.PG3 //
WIFI_BT_12 = allwinner.PG11 //
WIFI_BT_13 = allwinner.PG4 //
WIFI_BT_14 = allwinner.PG12 //
WIFI_BT_15 = allwinner.PG5 //
WIFI_BT_16 = allwinner.PG13 //
WIFI_BT_17 = allwinner.PL2 //
WIFI_BT_18 = pin.GROUND //
WIFI_BT_19 = allwinner.PL3 //
WIFI_BT_20 = allwinner.PL5 //
WIFI_BT_21 = allwinner.X32KFOUT //
WIFI_BT_22 = allwinner.PL5 //
WIFI_BT_23 = pin.GROUND //
WIFI_BT_24 = allwinner.PL6 //
WIFI_BT_25 = VCC //
WIFI_BT_26 = IOVCC //
AUDIO_LEFT = pin.INVALID // BUG(maruel): Fix once analog is implemented.
AUDIO_RIGHT = pin.INVALID //
)
//
// driver implements periph.Driver.
type driver struct {
}
func (d *driver) String() string {
return "pine64"
}
func (d *driver) Prerequisites() []string {
return nil
}
func (d *driver) After() []string {
return []string{"allwinner-gpio", "allwinner-gpio-pl"}
}
func (d *driver) Init() (bool, error) {
if !Present() {
return false, errors.New("pine64 board not detected")
}
if err := pinreg.Register("P1", [][]pin.Pin{
{P1_1, P1_2},
{P1_3, P1_4},
{P1_5, P1_6},
{P1_7, P1_8},
{P1_9, P1_10},
{P1_11, P1_12},
{P1_13, P1_14},
{P1_15, P1_16},
{P1_17, P1_18},
{P1_19, P1_20},
{P1_21, P1_22},
{P1_23, P1_24},
{P1_25, P1_26},
{P1_27, P1_28},
{P1_29, P1_30},
{P1_31, P1_32},
{P1_33, P1_34},
{P1_35, P1_36},
{P1_37, P1_38},
{P1_39, P1_40},
}); err != nil {
return true, err
}
if err := pinreg.Register("EULER", [][]pin.Pin{
{EULER_1, EULER_2},
{EULER_3, EULER_4},
{EULER_5, EULER_6},
{EULER_7, EULER_8},
{EULER_9, EULER_10},
{EULER_11, EULER_12},
{EULER_13, EULER_14},
{EULER_15, EULER_16},
{EULER_17, EULER_18},
{EULER_19, EULER_20},
{EULER_21, EULER_22},
{EULER_23, EULER_24},
{EULER_25, EULER_26},
{EULER_27, EULER_28},
{EULER_29, EULER_30},
{EULER_31, EULER_32},
{EULER_33, EULER_34},
}); err != nil {
return true, err
}
if err := pinreg.Register("EXP", [][]pin.Pin{
{EXP_1, EXP_2},
{EXP_3, EXP_4},
{EXP_5, EXP_6},
{EXP_7, EXP_8},
{EXP_9, EXP_10},
}); err != nil {
return true, err
}
if err := pinreg.Register("WIFI_BT", [][]pin.Pin{
{WIFI_BT_1, WIFI_BT_2},
{WIFI_BT_3, WIFI_BT_4},
{WIFI_BT_5, WIFI_BT_6},
{WIFI_BT_7, WIFI_BT_8},
{WIFI_BT_9, WIFI_BT_10},
{WIFI_BT_11, WIFI_BT_12},
{WIFI_BT_13, WIFI_BT_14},
{WIFI_BT_15, WIFI_BT_16},
{WIFI_BT_17, WIFI_BT_18},
{WIFI_BT_19, WIFI_BT_20},
{WIFI_BT_21, WIFI_BT_22},
{WIFI_BT_23, WIFI_BT_24},
{WIFI_BT_25, WIFI_BT_26},
}); err != nil {
return true, err
}
if err := pinreg.Register("AUDIO", [][]pin.Pin{
{AUDIO_LEFT},
{AUDIO_RIGHT},
}); err != nil {
return true, err
}
return true, nil
}
func init() {
if isArm {
periph.MustRegister(&drv)
}
}
var drv driver

7
vendor/periph.io/x/periph/host/pine64/pine64_arm.go generated vendored Normal file
View File

@ -0,0 +1,7 @@
// 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 pine64
const isArm = true

View File

@ -0,0 +1,9 @@
// 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.
// +build arm64
package pine64
const isArm = true

View File

@ -0,0 +1,9 @@
// 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.
// +build !arm,!arm64
package pine64
const isArm = false

182
vendor/periph.io/x/periph/host/pmem/alloc.go generated vendored Normal file
View File

@ -0,0 +1,182 @@
// 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 pmem
import (
"bytes"
"io"
"io/ioutil"
"reflect"
"sync"
"unsafe"
)
const pageSize = 4096
// Mem represents a section of memory that is usable by the DMA controller.
//
// Since this is physically allocated memory, that could potentially have been
// allocated in spite of OS consent, for example by asking the GPU directly, it
// is important to call Close() before process exit.
type Mem interface {
io.Closer
// Bytes returns the user space memory mapped buffer address as a slice of
// bytes.
//
// It is the raw view of the memory from this process.
Bytes() []byte
// AsPOD initializes a pointer to a POD (plain old data) to point to the
// memory mapped region.
//
// pp must be a pointer to:
//
// - pointer to a base size type (uint8, int64, float32, etc)
// - struct
// - array of the above
// - slice of the above
//
// and the value must be nil. Returns an error otherwise.
//
// If a pointer to a slice is passed in, it is initialized to the length and
// capacity set to the maximum number of elements this slice can represent.
//
// The pointer initialized points to the same address as Bytes().
AsPOD(pp interface{}) error
// PhysAddr is the physical address. It can be either 32 bits or 64 bits,
// depending on the bitness of the OS kernel, not on the user mode build,
// e.g. you could have compiled on a 32 bits Go toolchain but running on a
// 64 bits kernel.
PhysAddr() uint64
}
// MemAlloc represents contiguous physically locked memory that was allocated.
//
// The memory is mapped in user space.
//
// MemAlloc implements Mem.
type MemAlloc struct {
View
}
// Close unmaps the physical memory allocation.
func (m *MemAlloc) Close() error {
if err := munlock(m.orig); err != nil {
return err
}
return munmap(m.orig)
}
// Alloc allocates a continuous chunk of physical memory.
//
// Size must be rounded to 4Kb. Allocations of 4Kb will normally succeed.
// Allocations larger than 64Kb will likely fail due to kernel memory
// fragmentation; rebooting the host or reducing the number of running programs
// may help.
//
// The allocated memory is uncached.
func Alloc(size int) (*MemAlloc, error) {
if size == 0 || size&(pageSize-1) != 0 {
return nil, wrapf("allocated memory must be rounded to %d bytes", pageSize)
}
if isLinux && !isWSL() {
return allocLinux(size)
}
return nil, wrapf("memory allocation is not supported on this platform")
}
//
var (
wslOnce sync.Once
isWSLValue bool
)
// uallocMemLocked allocates user space memory and requests the OS to have the
// chunk to be locked into physical memory.
func uallocMemLocked(size int) ([]byte, error) {
// It is important to write to the memory so it is forced to be present.
b, err := uallocMem(size)
if err == nil {
for i := range b {
b[i] = 0
}
if err := mlock(b); err != nil {
// Ignore the unmap error.
_ = munmap(b)
return nil, wrapf("locking %d bytes failed: %v", size, err)
}
}
return b, err
}
// allocLinux allocates physical memory and returns a user view to it.
func allocLinux(size int) (*MemAlloc, error) {
// TODO(maruel): Implement the "shotgun approach". Allocate a ton of 4Kb
// pages and lock them. Then look at their physical pages and only keep the
// one useful. Then create a linear mapping in memory to simplify the user
// mode with a single linear user space virtual address but keep the
// individual page alive with their initial allocation. When done release
// each individual page.
if size > pageSize {
return nil, wrapf("large allocation is not yet implemented")
}
// First allocate a chunk of user space memory.
b, err := uallocMemLocked(size)
if err != nil {
return nil, err
}
pages := make([]uint64, (size+pageSize-1)/pageSize)
// Figure out the physical memory addresses.
for i := range pages {
pages[i], err = virtToPhys(toRaw(b[pageSize*i:]))
if err != nil {
return nil, err
}
if pages[i] == 0 {
return nil, wrapf("failed to read page %d", i)
}
}
for i := 1; i < len(pages); i++ {
// Fail if the memory is not contiguous.
if pages[i] != pages[i-1]+pageSize {
return nil, wrapf("failed to allocate %d bytes of continugous physical memory; page %d =0x%x; page %d=0x%x", size, i, pages[i], i-1, pages[i-1])
}
}
return &MemAlloc{View{Slice: b, phys: pages[0], orig: b}}, nil
}
// virtToPhys returns the physical memory address backing a virtual
// memory address.
func virtToPhys(virt uintptr) (uint64, error) {
physPage, err := ReadPageMap(virt)
if err != nil {
return 0, err
}
if physPage&(1<<63) == 0 {
// If high bit is not set, the page doesn't exist.
return 0, wrapf("0x%08x has no physical address", virt)
}
// Strip flags. See linux documentation on kernel.org for more details.
physPage &^= 0x1FF << 55
return physPage * pageSize, nil
}
func toRaw(b []byte) uintptr {
header := *(*reflect.SliceHeader)(unsafe.Pointer(&b))
return header.Data
}
// isWSL returns true if running under Windows Subsystem for Linux.
func isWSL() bool {
wslOnce.Do(func() {
if c, err := ioutil.ReadFile("/proc/sys/kernel/osrelease"); err == nil {
isWSLValue = bytes.Contains(c, []byte("Microsoft"))
}
})
return isWSLValue
}
var _ Mem = &MemAlloc{}

69
vendor/periph.io/x/periph/host/pmem/doc.go generated vendored Normal file
View File

@ -0,0 +1,69 @@
// 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 pmem implements handling of physical memory for user space programs.
//
// To make things confusing, a modern computer has many view of the memory
// (address spaces):
//
// User
//
// User mode address space is the virtual address space that an application
// runs in. It is generally a tad less than half the addressable memory, so on
// a 32 bits system, the addressable range is 1.9Gb. For 64 bits OS, it depends
// but it usually at least 3.5Gb. The memory is virtual and can be flushed to
// disk in the swap file unless individual pages are locked.
//
// Kernel
//
// Kernel address space is the virtual address space the kernel sees. It often
// can see the currently active user space program on the current CPU core in
// addition to all the memory the kernel sees. The kernel memory pages that are
// not mlock()'ed are 'virtual' and can be flushed to disk in the swap file
// when there's not enough RAM available. On linux systems, the kernel
// addressed memory can be mapped in user space via `/dev/kmem`.
//
// Physical
//
// Physical memory address space is the actual address of each page in the DRAM
// chip and anything connected to the memory controller. The mapping may be
// different depending on what controller looks at the bus, like with IOMMU. So
// a peripheral (GPU, DMA controller) may have a different view of the physical
// memory than the host CPU. On linux systems, this memory can be mapped in
// user space via `/dev/mem`.
//
// CPU
//
// The CPU or its subsystems may memory map registers (for example, to control
// GPIO pins, clock speed, etc). This is not "real" memory, this is a view of
// registers but it still follows "mostly" the same semantic as DRAM backed
// physical memory.
//
// Some CPU memory may have very special semantic where the mere fact of
// reading has side effects. For example reading a specific register may
// latches another.
//
// CPU memory accesses are layered with multiple caches, usually named L1, L2
// and optionally L3. Some controllers (DMA) can see some cache levels (L2) but
// not others (L1) on some CPU architecture (bcm283x). This means that a user
// space program writing data to a memory page and immediately asking the DMA
// controller to read it may cause stale data to be read!
//
// Hypervisor
//
// Hypervisor can change the complete memory mapping as seen by the kernel.
// This is outside the scope of this project. :)
//
// Summary
//
// In practice, the semantics change between CPU manufacturers (Broadcom vs
// Allwinner) and between architectures (ARM vs x86). The most tricky one is to
// understand cached memory and how it affects coherence and performance.
// Uncached memory is extremely slow so it must only be used when necessary.
//
// References
//
// Overview of IOMMU:
// https://en.wikipedia.org/wiki/Input-output_memory_management_unit
package pmem

56
vendor/periph.io/x/periph/host/pmem/mem_linux.go generated vendored Normal file
View File

@ -0,0 +1,56 @@
// 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 pmem
import "syscall"
const isLinux = true
func mmap(fd uintptr, offset int64, length int) ([]byte, error) {
v, err := syscall.Mmap(int(fd), offset, length, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED)
if err != nil {
return nil, wrapf("failed to memory map: %v", err)
}
return v, nil
}
func munmap(b []byte) error {
if err := syscall.Munmap(b); err != nil {
return wrapf("failed to unmap memory: %v", err)
}
return nil
}
func mlock(b []byte) error {
if err := syscall.Mlock(b); err != nil {
return wrapf("failed to lock memory: %v", err)
}
return nil
}
func munlock(b []byte) error {
if err := syscall.Munlock(b); err != nil {
return wrapf("failed to unlock memory: %v", err)
}
return nil
}
// uallocMem allocates user space memory.
func uallocMem(size int) ([]byte, error) {
b, err := syscall.Mmap(
0,
0,
size,
syscall.PROT_READ|syscall.PROT_WRITE,
syscall.MAP_ANONYMOUS|syscall.MAP_LOCKED|syscall.MAP_NORESERVE|syscall.MAP_SHARED)
// syscall.MAP_HUGETLB / MAP_HUGE_2MB
// See /sys/kernel/mm/hugepages but both C.H.I.P. running Jessie and Raspbian
// Jessie do not expose huge pages. :(
if err != nil {
return nil, wrapf("allocating %d bytes failed: %v", size, err)
}
return b, err
}

30
vendor/periph.io/x/periph/host/pmem/mem_other.go generated vendored Normal file
View File

@ -0,0 +1,30 @@
// 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.
// +build !linux
package pmem
const isLinux = false
func mmap(fd uintptr, offset int64, length int) ([]byte, error) {
return nil, wrapf("syscall.Mmap() not implemented on this OS")
}
func munmap(b []byte) error {
return wrapf("syscall.Munmap() not implemented on this OS")
}
func mlock(b []byte) error {
return wrapf("syscall.Mlock() not implemented on this OS")
}
func munlock(b []byte) error {
return wrapf("syscall.Munlock() not implemented on this OS")
}
// uallocMem allocates user space memory.
func uallocMem(size int) ([]byte, error) {
return make([]byte, size), nil
}

64
vendor/periph.io/x/periph/host/pmem/pagemap.go generated vendored Normal file
View File

@ -0,0 +1,64 @@
// 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 pmem
import (
"encoding/binary"
"errors"
"fmt"
"os"
)
// ReadPageMap reads a physical address mapping for a virtual page address from
// /proc/self/pagemap.
//
// It returns the physical address that corresponds to the start of the virtual
// page within which the virtual address virtAddr is located.
//
// The meaning of the return value is documented at
// https://www.kernel.org/doc/Documentation/vm/pagemap.txt
func ReadPageMap(virtAddr uintptr) (uint64, error) {
if !isLinux || isWSL() {
return 0, errors.New("pmem: pagemap is not supported on this platform")
}
return readPageMapLinux(virtAddr)
}
//
var (
pageMap fileIO
pageMapErr error
)
func readPageMapLinux(virtAddr uintptr) (uint64, error) {
var b [8]byte
mu.Lock()
defer mu.Unlock()
if pageMap == nil && pageMapErr == nil {
// Open /proc/self/pagemap.
//
// It is a uint64 array where the index represents the virtual 4Kb page
// number and the value represents the physical page properties backing
// this virtual page.
pageMap, pageMapErr = openFile("/proc/self/pagemap", os.O_RDONLY|os.O_SYNC)
}
if pageMapErr != nil {
return 0, pageMapErr
}
// Convert address to page number, then index in uint64 array.
offset := int64(virtAddr / pageSize * 8)
if _, err := pageMap.Seek(offset, os.SEEK_SET); err != nil {
return 0, fmt.Errorf("pmem: failed to seek at 0x%x for 0x%x: %v", offset, virtAddr, err)
}
n, err := pageMap.Read(b[:])
if err != nil {
return 0, fmt.Errorf("pmem: failed to read at 0x%x for 0x%x: %v", offset, virtAddr, err)
}
if n != len(b) {
return 0, fmt.Errorf("pmem: failed to read the amount of data %d", len(b))
}
return binary.LittleEndian.Uint64(b[:]), nil
}

89
vendor/periph.io/x/periph/host/pmem/smoketest.go generated vendored Normal file
View File

@ -0,0 +1,89 @@
// 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 pmem
import (
"bytes"
"math/rand"
)
// TestCopy is used by CPU drivers to verify that the DMA engine works
// correctly.
//
// It is not meant to be used by end users.
//
// TestCopy allocates two buffer via `alloc`, once as the source and one as the
// destination. It fills the source with random data and the destination with
// 0x11.
//
// `copyMem` is expected to copy the memory from pSrc to pDst, with an offset
// of `hole` and size `size-2*hole`.
//
// The function `copyMem` being tested is only given the buffer physical
// addresses and must copy the data without other help. It is expected to
//
// This confirm misaligned DMA copying works.
// leverage the host's DMA engine.
func TestCopy(size, holeSize int, alloc func(size int) (Mem, error), copyMem func(pDst, pSrc uint64) error) error {
pSrc, err2 := alloc(size)
if err2 != nil {
return err2
}
defer pSrc.Close()
pDst, err2 := alloc(size)
if err2 != nil {
return err2
}
defer pDst.Close()
dst := pDst.Bytes()
for i := range dst {
dst[i] = 0x11
}
src := make([]byte, size)
for i := range src {
src[i] = byte(rand.Int31())
}
copy(pSrc.Bytes(), src[:])
// Run the driver supplied memory copying code.
if err := copyMem(pDst.PhysAddr(), pSrc.PhysAddr()); err != nil {
return err
}
// Verifications.
for i := 0; i < holeSize; i++ {
if dst[i] != 0x11 {
return wrapf("DMA corrupted the buffer header: %x", dst[:holeSize])
}
if dst[size-1-i] != 0x11 {
return wrapf("DMA corrupted the buffer footer: %x", dst[size-1-holeSize:])
}
}
// Headers and footers were not corupted in the destination. Verify the inner
// view that should match.
x := src[:size-2*holeSize]
y := dst[holeSize : size-holeSize]
if !bytes.Equal(x, y) {
offset := 0
for len(x) != 0 && x[0] == y[0] {
x = x[1:]
y = y[1:]
offset++
}
for len(x) != 0 && x[len(x)-1] == y[len(y)-1] {
x = x[:len(x)-1]
y = y[:len(y)-1]
}
if len(x) > 32 {
x = x[:32]
}
if len(y) > 32 {
y = y[:32]
}
return wrapf("DMA corrupted the buffer at offset %d:\n%x\n%x", offset, x, y)
}
return nil
}

283
vendor/periph.io/x/periph/host/pmem/view.go generated vendored Normal file
View File

@ -0,0 +1,283 @@
// 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 pmem
import (
"fmt"
"io"
"os"
"reflect"
"sync"
"unsafe"
"periph.io/x/periph/host/fs"
)
// Slice can be transparently viewed as []byte, []uint32 or a struct.
type Slice []byte
// Uint32 returns a view of the byte slice as a []uint32.
func (s *Slice) Uint32() []uint32 {
header := *(*reflect.SliceHeader)(unsafe.Pointer(s))
header.Len /= 4
header.Cap /= 4
return *(*[]uint32)(unsafe.Pointer(&header))
}
// Bytes implements Mem.
func (s *Slice) Bytes() []byte {
return *s
}
// AsPOD implements Mem.
func (s *Slice) AsPOD(pp interface{}) error {
if pp == nil {
return wrapf("require Ptr, got nil")
}
vpp := reflect.ValueOf(pp)
if elemSize, err := isPS(len(*s), vpp); err == nil {
p := vpp.Elem()
t := p.Type().Elem()
if elemSize > len(*s) {
return wrapf("can't map slice of struct %s (size %d) on [%d]byte", t, elemSize, len(*s))
}
nbElems := len(*s) / elemSize
// Use casting black magic to set the internal slice headers.
hdr := (*reflect.SliceHeader)(unsafe.Pointer(p.UnsafeAddr()))
hdr.Data = ((*reflect.SliceHeader)(unsafe.Pointer(s))).Data
hdr.Len = nbElems
hdr.Cap = nbElems
return nil
}
size, err := isPP(vpp)
if err != nil {
return err
}
p := vpp.Elem()
t := p.Type().Elem()
if size > len(*s) {
return wrapf("can't map struct %s (size %d) on [%d]byte", t, size, len(*s))
}
// Use casting black magic to read the internal slice headers.
dest := unsafe.Pointer(((*reflect.SliceHeader)(unsafe.Pointer(s))).Data)
// Use reflection black magic to write to the original pointer.
p.Set(reflect.NewAt(t, dest))
return nil
}
// View represents a view of physical memory memory mapped into user space.
//
// It is usually used to map CPU registers into user space, usually I/O
// registers and the likes.
//
// It is not required to call Close(), the kernel will clean up on process
// shutdown.
type View struct {
Slice
orig []uint8 // Reference rounded to the lowest 4Kb page containing Slice.
phys uint64 // physical address of the base of Slice.
}
// Close unmaps the memory from the user address space.
//
// This is done naturally by the OS on process teardown (when the process
// exits) so this is not a hard requirement to call this function.
func (v *View) Close() error {
return munmap(v.orig)
}
// PhysAddr implements Mem.
func (v *View) PhysAddr() uint64 {
return v.phys
}
// MapGPIO returns a CPU specific memory mapping of the CPU I/O registers using
// /dev/gpiomem.
//
// At the moment, /dev/gpiomem is only supported on Raspbian Jessie via a
// specific kernel driver.
func MapGPIO() (*View, error) {
if isLinux {
return mapGPIOLinux()
}
return nil, wrapf("/dev/gpiomem is not supported on this platform")
}
// Map returns a memory mapped view of arbitrary physical memory range using OS
// provided functionality.
//
// Maps size of memory, rounded on a 4kb window.
//
// This function is dangerous and should be used wisely. It normally requires
// super privileges (root). On Linux, it leverages /dev/mem.
func Map(base uint64, size int) (*View, error) {
if isLinux {
return mapLinux(base, size)
}
return nil, wrapf("physical memory mapping is not supported on this platform")
}
// MapAsPOD is a leaky shorthand of calling Map(base, sizeof(v)) then AsPOD(v).
//
// There is no way to reclaim the memory map.
//
// A slice cannot be used, as it does not have inherent size. Use an aray
// instead.
func MapAsPOD(base uint64, i interface{}) error {
// Automatically determine the necessary size. Because of this, slice of
// unspecified length cannot be used here.
if i == nil {
return wrapf("require Ptr, got nil")
}
v := reflect.ValueOf(i)
size, err := isPP(v)
if err != nil {
return err
}
m, err := Map(base, size)
if err != nil {
return err
}
return m.AsPOD(i)
}
//
// Keep a cache of open file handles instead of opening and closing repeatedly.
var (
mu sync.Mutex
gpioMemErr error
gpioMemView *View
devMem fileIO
devMemErr error
openFile = openFileOrig
)
type fileIO interface {
io.Closer
io.Seeker
io.Reader
Fd() uintptr
}
func openFileOrig(path string, flag int) (fileIO, error) {
f, err := fs.Open(path, flag)
if err != nil {
return nil, err
}
return f, nil
}
// mapGPIOLinux is purely Raspbian specific.
func mapGPIOLinux() (*View, error) {
mu.Lock()
defer mu.Unlock()
if gpioMemView == nil && gpioMemErr == nil {
if f, err := openFile("/dev/gpiomem", os.O_RDWR|os.O_SYNC); err == nil {
defer f.Close()
if i, err := mmap(f.Fd(), 0, pageSize); err == nil {
gpioMemView = &View{Slice: i, orig: i, phys: 0}
} else {
gpioMemErr = wrapf("failed to memory map in user space GPIO memory: %v", err)
}
} else {
gpioMemErr = wrapf("failed to open GPIO memory: %v", err)
}
}
return gpioMemView, gpioMemErr
}
// mapLinux leverages /dev/mem to map a view of physical memory.
func mapLinux(base uint64, size int) (*View, error) {
f, err := openDevMemLinux()
if err != nil {
return nil, err
}
// Align base and size at 4Kb.
offset := int(base & 0xFFF)
i, err := mmap(f.Fd(), int64(base&^0xFFF), (size+offset+0xFFF)&^0xFFF)
if err != nil {
return nil, wrapf("mapping at 0x%x failed: %v", base, err)
}
return &View{Slice: i[offset : offset+size], orig: i, phys: base + uint64(offset)}, nil
}
func openDevMemLinux() (fileIO, error) {
mu.Lock()
defer mu.Unlock()
if devMem == nil && devMemErr == nil {
if devMem, devMemErr = openFile("/dev/mem", os.O_RDWR|os.O_SYNC); devMemErr != nil {
devMemErr = wrapf("failed to open physical memory: %v", devMemErr)
}
}
return devMem, devMemErr
}
func isAcceptableInner(t reflect.Type) error {
switch k := t.Kind(); k {
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
reflect.Float32, reflect.Float64:
return nil
case reflect.Array:
return isAcceptableInner(t.Elem())
case reflect.Struct:
for i := 0; i < t.NumField(); i++ {
if err := isAcceptableInner(t.Field(i).Type); err != nil {
return err
}
}
return nil
default:
return wrapf("require Ptr to Ptr to a POD type, got Ptr to Ptr to %s", k)
}
}
// isPP makes sure it is a pointer to a nil-pointer to something. It does
// sanity checks to reduce likelihood of a panic().
func isPP(pp reflect.Value) (int, error) {
if k := pp.Kind(); k != reflect.Ptr {
return 0, wrapf("require Ptr, got %s of %s", k, pp.Type().Name())
}
p := pp.Elem()
if k := p.Kind(); k != reflect.Ptr {
return 0, wrapf("require Ptr to Ptr, got %s", k)
}
if !p.IsNil() {
return 0, wrapf("require Ptr to Ptr to be nil")
}
// p.Elem() can't be used since it's a nil pointer. Use the type instead.
t := p.Type().Elem()
if err := isAcceptableInner(t); err != nil {
return 0, err
}
return int(t.Size()), nil
}
// isPS makes sure it is a pointer to a nil-slice of something. It does
// sanity checks to reduce likelihood of a panic().
func isPS(bufSize int, ps reflect.Value) (int, error) {
if k := ps.Kind(); k != reflect.Ptr {
return 0, wrapf("require Ptr, got %s of %s", k, ps.Type().Name())
}
s := ps.Elem()
if k := s.Kind(); k != reflect.Slice {
return 0, wrapf("require Ptr to Slice, got %s", k)
}
if !s.IsNil() {
return 0, wrapf("require Ptr to Slice to be nil")
}
// s.Elem() can't be used since it's a nil slice. Use the type instead.
t := s.Type().Elem()
if err := isAcceptableInner(t); err != nil {
return 0, err
}
return int(t.Size()), nil
}
func wrapf(format string, a ...interface{}) error {
return fmt.Errorf("pmem: "+format, a...)
}

15
vendor/periph.io/x/periph/host/rpi/doc.go generated vendored Normal file
View File

@ -0,0 +1,15 @@
// 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 rpi contains Raspberry Pi hardware logic. It is intrinsically
// related to package bcm283x.
//
// Assumes Raspbian but does not directly depend on the distro being Raspbian.
// Windows IoT is currently not supported.
//
// Physical
//
// The physical pin out is based on http://www.raspberrypi.org information but
// http://pinout.xyz/ has a nice interactive web page.
package rpi

815
vendor/periph.io/x/periph/host/rpi/rpi.go generated vendored Normal file
View File

@ -0,0 +1,815 @@
// 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.
// Raspberry Pi pin out.
package rpi
import (
"errors"
"fmt"
"os"
"strconv"
"periph.io/x/periph"
"periph.io/x/periph/conn/gpio"
"periph.io/x/periph/conn/pin"
"periph.io/x/periph/conn/pin/pinreg"
"periph.io/x/periph/host/bcm283x"
"periph.io/x/periph/host/distro"
)
// Present returns true if running on a Raspberry Pi board.
//
// https://www.raspberrypi.org/
func Present() bool {
if isArm {
// This is iffy at best.
_, err := os.Stat("/sys/bus/platform/drivers/raspberrypi-firmware")
return err == nil
}
return false
}
// Pin as connect on the 40 pins extension header.
//
// Schematics are useful to know what is connected to what:
// https://www.raspberrypi.org/documentation/hardware/raspberrypi/schematics/README.md
//
// The actual pin mapping depends on the board revision! The default values are
// set as the 40 pins header on Raspberry Pi 2 and Raspberry Pi 3.
//
// Some header info here: http://elinux.org/RPi_Low-level_peripherals
//
// P1 is also known as J8 on A+, B+, 2 and later.
var (
// Raspberry Pi A and B, 26 pin header:
P1_1 pin.Pin = pin.V3_3 // max 30mA
P1_2 pin.Pin = pin.V5 // (filtered)
P1_3 gpio.PinIO = bcm283x.GPIO2 // High, I2C1_SDA
P1_4 pin.Pin = pin.V5 //
P1_5 gpio.PinIO = bcm283x.GPIO3 // High, I2C1_SCL
P1_6 pin.Pin = pin.GROUND //
P1_7 gpio.PinIO = bcm283x.GPIO4 // High, CLK0
P1_8 gpio.PinIO = bcm283x.GPIO14 // Low, UART0_TX, UART1_TX
P1_9 pin.Pin = pin.GROUND //
P1_10 gpio.PinIO = bcm283x.GPIO15 // Low, UART0_RX, UART1_RX
P1_11 gpio.PinIO = bcm283x.GPIO17 // Low, UART0_RTS, SPI1_CS1, UART1_RTS
P1_12 gpio.PinIO = bcm283x.GPIO18 // Low, I2S_SCK, SPI1_CS0, PWM0
P1_13 gpio.PinIO = bcm283x.GPIO27 // Low,
P1_14 pin.Pin = pin.GROUND //
P1_15 gpio.PinIO = bcm283x.GPIO22 // Low,
P1_16 gpio.PinIO = bcm283x.GPIO23 // Low,
P1_17 pin.Pin = pin.V3_3 //
P1_18 gpio.PinIO = bcm283x.GPIO24 // Low,
P1_19 gpio.PinIO = bcm283x.GPIO10 // Low, SPI0_MOSI
P1_20 pin.Pin = pin.GROUND //
P1_21 gpio.PinIO = bcm283x.GPIO9 // Low, SPI0_MISO
P1_22 gpio.PinIO = bcm283x.GPIO25 // Low,
P1_23 gpio.PinIO = bcm283x.GPIO11 // Low, SPI0_CLK
P1_24 gpio.PinIO = bcm283x.GPIO8 // High, SPI0_CS0
P1_25 pin.Pin = pin.GROUND //
P1_26 gpio.PinIO = bcm283x.GPIO7 // High, SPI0_CS1
// Raspberry Pi A+, B+, 2 and later, 40 pin header (also named J8):
P1_27 gpio.PinIO = bcm283x.GPIO0 // High, I2C0_SDA used to probe for HAT EEPROM, see https://github.com/raspberrypi/hats
P1_28 gpio.PinIO = bcm283x.GPIO1 // High, I2C0_SCL
P1_29 gpio.PinIO = bcm283x.GPIO5 // High, CLK1
P1_30 pin.Pin = pin.GROUND //
P1_31 gpio.PinIO = bcm283x.GPIO6 // High, CLK2
P1_32 gpio.PinIO = bcm283x.GPIO12 // Low, PWM0
P1_33 gpio.PinIO = bcm283x.GPIO13 // Low, PWM1
P1_34 pin.Pin = pin.GROUND //
P1_35 gpio.PinIO = bcm283x.GPIO19 // Low, I2S_WS, SPI1_MISO, PWM1
P1_36 gpio.PinIO = bcm283x.GPIO16 // Low, UART0_CTS, SPI1_CS2, UART1_CTS
P1_37 gpio.PinIO = bcm283x.GPIO26 //
P1_38 gpio.PinIO = bcm283x.GPIO20 // Low, I2S_DIN, SPI1_MOSI, CLK0
P1_39 pin.Pin = pin.GROUND //
P1_40 gpio.PinIO = bcm283x.GPIO21 // Low, I2S_DOUT, SPI1_CLK, CLK1
// P5 header on Raspberry Pi A and B, PCB v2:
P5_1 pin.Pin = pin.V5
P5_2 pin.Pin = pin.V3_3
P5_3 gpio.PinIO = bcm283x.GPIO28 // Float, I2C0_SDA, I2S_SCK
P5_4 gpio.PinIO = bcm283x.GPIO29 // Float, I2C0_SCL, I2S_WS
P5_5 gpio.PinIO = bcm283x.GPIO30 // Low, I2S_DIN, UART0_CTS, UART1_CTS
P5_6 gpio.PinIO = bcm283x.GPIO31 // Low, I2S_DOUT, UART0_RTS, UART1_RTS
P5_7 pin.Pin = pin.GROUND
P5_8 pin.Pin = pin.GROUND
AUDIO_RIGHT = bcm283x.GPIO40 // Low, PWM0, SPI2_MISO, UART1_TX
AUDIO_LEFT = bcm283x.GPIO41 // Low, PWM1, SPI2_MOSI, UART1_RX
HDMI_HOTPLUG_DETECT = bcm283x.GPIO46 // High,
)
// Pin as connected on the SODIMM header.
//
// Documentation is https://www.raspberrypi.org/documentation/hardware/computemodule/datasheets/rpi_DATA_CM_1p0.pdf
//
// There are some differences for CM3-Lite and CM1.
var (
SO_1 pin.Pin = pin.GROUND // GND
SO_2 pin.Pin = pin.INVALID // EMMC_DISABLE_N
SO_3 gpio.PinIO = bcm283x.GPIO0 // GPIO0
SO_4 pin.Pin = pin.INVALID // NC, SDX_VDD, NC
SO_5 gpio.PinIO = bcm283x.GPIO1 // GPIO1
SO_6 pin.Pin = pin.INVALID // NC, SDX_VDD, NC
SO_7 pin.Pin = pin.GROUND // GND
SO_8 pin.Pin = pin.GROUND // GND
SO_9 gpio.PinIO = bcm283x.GPIO2 // GPIO2
SO_10 pin.Pin = pin.INVALID // NC, SDX_CLK, NC
SO_11 gpio.PinIO = bcm283x.GPIO3 // GPIO3
SO_12 pin.Pin = pin.INVALID // NC, SDX_CMD, NC
SO_13 pin.Pin = pin.GROUND // GND
SO_14 pin.Pin = pin.GROUND // GND
SO_15 gpio.PinIO = bcm283x.GPIO4 // GPIO4
SO_16 pin.Pin = pin.INVALID // NC, SDX_D0, NC
SO_17 gpio.PinIO = bcm283x.GPIO5 // GPIO5
SO_18 pin.Pin = pin.INVALID // NC, SDX_D1, NC
SO_19 pin.Pin = pin.GROUND // GND
SO_20 pin.Pin = pin.GROUND // GND
SO_21 gpio.PinIO = bcm283x.GPIO6 // GPIO6
SO_22 pin.Pin = pin.INVALID // NC, SDX_D2, NC
SO_23 gpio.PinIO = bcm283x.GPIO7 // GPIO7
SO_24 pin.Pin = pin.INVALID // NC, SDX_D3, NC
SO_25 pin.Pin = pin.GROUND // GND
SO_26 pin.Pin = pin.GROUND // GND
SO_27 gpio.PinIO = bcm283x.GPIO8 // GPIO8
SO_28 gpio.PinIO = bcm283x.GPIO28 // GPIO28
SO_29 gpio.PinIO = bcm283x.GPIO9 // GPIO9
SO_30 gpio.PinIO = bcm283x.GPIO29 // GPIO29
SO_31 pin.Pin = pin.GROUND // GND
SO_32 pin.Pin = pin.GROUND // GND
SO_33 gpio.PinIO = bcm283x.GPIO10 // GPIO10
SO_34 gpio.PinIO = bcm283x.GPIO30 // GPIO30
SO_35 gpio.PinIO = bcm283x.GPIO11 // GPIO11
SO_36 gpio.PinIO = bcm283x.GPIO31 // GPIO31
SO_37 pin.Pin = pin.GROUND // GND
SO_38 pin.Pin = pin.GROUND // GND
SO_39 pin.Pin = pin.DC_IN // GPIO0-27_VDD
SO_40 pin.Pin = pin.DC_IN // GPIO0-27_VDD
SO_41 pin.Pin = pin.DC_IN // GPIO28-45_VDD
SO_42 pin.Pin = pin.DC_IN // GPIO28-45_VDD
SO_43 pin.Pin = pin.GROUND // GND
SO_44 pin.Pin = pin.GROUND // GND
SO_45 gpio.PinIO = bcm283x.GPIO12 // GPIO12
SO_46 gpio.PinIO = bcm283x.GPIO32 // GPIO32
SO_47 gpio.PinIO = bcm283x.GPIO13 // GPIO13
SO_48 gpio.PinIO = bcm283x.GPIO33 // GPIO33
SO_49 pin.Pin = pin.GROUND // GND
SO_50 pin.Pin = pin.GROUND // GND
SO_51 gpio.PinIO = bcm283x.GPIO14 // GPIO14
SO_52 gpio.PinIO = bcm283x.GPIO34 // GPIO34
SO_53 gpio.PinIO = bcm283x.GPIO15 // GPIO15
SO_54 gpio.PinIO = bcm283x.GPIO35 // GPIO35
SO_55 pin.Pin = pin.GROUND // GND
SO_56 pin.Pin = pin.GROUND // GND
SO_57 gpio.PinIO = bcm283x.GPIO16 // GPIO16
SO_58 gpio.PinIO = bcm283x.GPIO36 // GPIO36
SO_59 gpio.PinIO = bcm283x.GPIO17 // GPIO17
SO_60 gpio.PinIO = bcm283x.GPIO37 // GPIO37
SO_61 pin.Pin = pin.GROUND // GND
SO_62 pin.Pin = pin.GROUND // GND
SO_63 gpio.PinIO = bcm283x.GPIO18 // GPIO18
SO_64 gpio.PinIO = bcm283x.GPIO38 // GPIO38
SO_65 gpio.PinIO = bcm283x.GPIO19 // GPIO19
SO_66 gpio.PinIO = bcm283x.GPIO39 // GPIO39
SO_67 pin.Pin = pin.GROUND // GND
SO_68 pin.Pin = pin.GROUND // GND
SO_69 gpio.PinIO = bcm283x.GPIO20 // GPIO20
SO_70 gpio.PinIO = bcm283x.GPIO40 // GPIO40
SO_71 gpio.PinIO = bcm283x.GPIO21 // GPIO21
SO_72 gpio.PinIO = bcm283x.GPIO41 // GPIO41
SO_73 pin.Pin = pin.GROUND // GND
SO_74 pin.Pin = pin.GROUND // GND
SO_75 gpio.PinIO = bcm283x.GPIO22 // GPIO22
SO_76 gpio.PinIO = bcm283x.GPIO42 // GPIO42
SO_77 gpio.PinIO = bcm283x.GPIO23 // GPIO23
SO_78 gpio.PinIO = bcm283x.GPIO43 // GPIO43
SO_79 pin.Pin = pin.GROUND // GND
SO_80 pin.Pin = pin.GROUND // GND
SO_81 gpio.PinIO = bcm283x.GPIO24 // GPIO24
SO_82 gpio.PinIO = bcm283x.GPIO44 // GPIO44
SO_83 gpio.PinIO = bcm283x.GPIO25 // GPIO25
SO_84 gpio.PinIO = bcm283x.GPIO45 // GPIO45
SO_85 pin.Pin = pin.GROUND // GND
SO_86 pin.Pin = pin.GROUND // GND
SO_87 gpio.PinIO = bcm283x.GPIO26 // GPIO26
SO_88 pin.Pin = pin.INVALID // HDMI_HPD_N_1V8, HDMI_HPD_N_1V8, GPIO46_1V8
SO_89 gpio.PinIO = bcm283x.GPIO27 // GPIO27
SO_90 pin.Pin = pin.INVALID // EMMC_EN_N_1V8, EMMC_EN_N_1V8, GPIO47_1V8
SO_91 pin.Pin = pin.GROUND // GND
SO_92 pin.Pin = pin.GROUND // GND
SO_93 pin.Pin = pin.INVALID // DSI0_DN1
SO_94 pin.Pin = pin.INVALID // DSI1_DP0
SO_95 pin.Pin = pin.INVALID // DSI0_DP1
SO_96 pin.Pin = pin.INVALID // DSI1_DN0
SO_97 pin.Pin = pin.GROUND // GND
SO_98 pin.Pin = pin.GROUND // GND
SO_99 pin.Pin = pin.INVALID // DSI0_DN0
SO_100 pin.Pin = pin.INVALID // DSI1_CP
SO_101 pin.Pin = pin.INVALID // DSI0_DP0
SO_102 pin.Pin = pin.INVALID // DSI1_CN
SO_103 pin.Pin = pin.GROUND // GND
SO_104 pin.Pin = pin.GROUND // GND
SO_105 pin.Pin = pin.INVALID // DSI0_CN
SO_106 pin.Pin = pin.INVALID // DSI1_DP3
SO_107 pin.Pin = pin.INVALID // DSI0_CP
SO_108 pin.Pin = pin.INVALID // DSI1_DN3
SO_109 pin.Pin = pin.GROUND // GND
SO_110 pin.Pin = pin.GROUND // GND
SO_111 pin.Pin = pin.INVALID // HDMI_CLK_N
SO_112 pin.Pin = pin.INVALID // DSI1_DP2
SO_113 pin.Pin = pin.INVALID // HDMI_CLK_P
SO_114 pin.Pin = pin.INVALID // DSI1_DN2
SO_115 pin.Pin = pin.GROUND // GND
SO_116 pin.Pin = pin.GROUND // GND
SO_117 pin.Pin = pin.INVALID // HDMI_D0_N
SO_118 pin.Pin = pin.INVALID // DSI1_DP1
SO_119 pin.Pin = pin.INVALID // HDMI_D0_P
SO_120 pin.Pin = pin.INVALID // DSI1_DN1
SO_121 pin.Pin = pin.GROUND // GND
SO_122 pin.Pin = pin.GROUND // GND
SO_123 pin.Pin = pin.INVALID // HDMI_D1_N
SO_124 pin.Pin = pin.INVALID // NC
SO_125 pin.Pin = pin.INVALID // HDMI_D1_P
SO_126 pin.Pin = pin.INVALID // NC
SO_127 pin.Pin = pin.GROUND // GND
SO_128 pin.Pin = pin.INVALID // NC
SO_129 pin.Pin = pin.INVALID // HDMI_D2_N
SO_130 pin.Pin = pin.INVALID // NC
SO_131 pin.Pin = pin.INVALID // HDMI_D2_P
SO_132 pin.Pin = pin.INVALID // NC
SO_133 pin.Pin = pin.GROUND // GND
SO_134 pin.Pin = pin.GROUND // GND
SO_135 pin.Pin = pin.INVALID // CAM1_DP3
SO_136 pin.Pin = pin.INVALID // CAM0_DP0
SO_137 pin.Pin = pin.INVALID // CAM1_DN3
SO_138 pin.Pin = pin.INVALID // CAM0_DN0
SO_139 pin.Pin = pin.GROUND // GND
SO_140 pin.Pin = pin.GROUND // GND
SO_141 pin.Pin = pin.INVALID // CAM1_DP2
SO_142 pin.Pin = pin.INVALID // CAM0_CP
SO_143 pin.Pin = pin.INVALID // CAM1_DN2
SO_144 pin.Pin = pin.INVALID // CAM0_CN
SO_145 pin.Pin = pin.GROUND // GND
SO_146 pin.Pin = pin.GROUND // GND
SO_147 pin.Pin = pin.INVALID // CAM1_CP
SO_148 pin.Pin = pin.INVALID // CAM0_DP1
SO_149 pin.Pin = pin.INVALID // CAM1_CN
SO_150 pin.Pin = pin.INVALID // CAM0_DN1
SO_151 pin.Pin = pin.GROUND // GND
SO_152 pin.Pin = pin.GROUND // GND
SO_153 pin.Pin = pin.INVALID // CAM1_DP1
SO_154 pin.Pin = pin.INVALID // NC
SO_155 pin.Pin = pin.INVALID // CAM1_DN1
SO_156 pin.Pin = pin.INVALID // NC
SO_157 pin.Pin = pin.GROUND // GND
SO_158 pin.Pin = pin.INVALID // NC
SO_159 pin.Pin = pin.INVALID // CAM1_DP0
SO_160 pin.Pin = pin.INVALID // NC
SO_161 pin.Pin = pin.INVALID // CAM1_DN0
SO_162 pin.Pin = pin.INVALID // NC
SO_163 pin.Pin = pin.GROUND // GND
SO_164 pin.Pin = pin.GROUND // GND
SO_165 pin.Pin = pin.INVALID // USB_DP
SO_166 pin.Pin = pin.INVALID // TVDAC
SO_167 pin.Pin = pin.INVALID // USB_DM
SO_168 pin.Pin = pin.INVALID // USB_OTGID
SO_169 pin.Pin = pin.GROUND // GND
SO_170 pin.Pin = pin.GROUND // GND
SO_171 pin.Pin = pin.INVALID // HDMI_CEC
SO_172 pin.Pin = pin.INVALID // VC_TRST_N
SO_173 pin.Pin = pin.INVALID // HDMI_SDA
SO_174 pin.Pin = pin.INVALID // VC_TDI
SO_175 pin.Pin = pin.INVALID // HDMI_SCL
SO_176 pin.Pin = pin.INVALID // VC_TMS
SO_177 pin.Pin = pin.INVALID // RUN
SO_178 pin.Pin = pin.INVALID // VC_TDO
SO_179 pin.Pin = pin.INVALID // VDD_CORE (DO NOT CONNECT)
SO_180 pin.Pin = pin.INVALID // VC_TCK
SO_181 pin.Pin = pin.GROUND // GND
SO_182 pin.Pin = pin.GROUND // GND
SO_183 pin.Pin = pin.V1_8 // 1V8
SO_184 pin.Pin = pin.V1_8 // 1V8
SO_185 pin.Pin = pin.V1_8 // 1V8
SO_186 pin.Pin = pin.V1_8 // 1V8
SO_187 pin.Pin = pin.GROUND // GND
SO_188 pin.Pin = pin.GROUND // GND
SO_189 pin.Pin = pin.DC_IN // VDAC
SO_190 pin.Pin = pin.DC_IN // VDAC
SO_191 pin.Pin = pin.V3_3 // 3V3
SO_192 pin.Pin = pin.V3_3 // 3V3
SO_193 pin.Pin = pin.V3_3 // 3V3
SO_194 pin.Pin = pin.V3_3 // 3V3
SO_195 pin.Pin = pin.GROUND // GND
SO_196 pin.Pin = pin.GROUND // GND
SO_197 pin.Pin = pin.DC_IN // VBAT
SO_198 pin.Pin = pin.DC_IN // VBAT
SO_199 pin.Pin = pin.DC_IN // VBAT
SO_200 pin.Pin = pin.DC_IN // VBAT
)
//
// revisionCode processes the CPU revision code based on documentation at
// https://www.raspberrypi.org/documentation/hardware/raspberrypi/revision-codes/README.md
//
// Format is: uuuuuuuuFMMMCCCCPPPPTTTTTTTTRRRR
// 2 2 1 1 0 0
// 3 0 6 2 4 0
type revisionCode uint32
// parseRevision processes the old style revision codes to new style bitpacked
// format.
func parseRevision(v uint32) (revisionCode, error) {
w := revisionCode(v) & warrantyVoid
switch v &^ uint32(warrantyVoid) {
case 0x2, 0x3:
return w | newFormat | memory256MB | egoman | bcm2835 | board1B, nil
case 0x4:
return w | newFormat | memory256MB | sonyUK | bcm2835 | board1B | 2, nil // v2.0
case 0x5:
return w | newFormat | memory256MB | bcm2835 | board1B | 2, nil // v2.0 Qisda
case 0x6:
return w | newFormat | memory256MB | egoman | bcm2835 | board1B | 2, nil // v2.0
case 0x7:
return w | newFormat | memory256MB | egoman | bcm2835 | board1A | 2, nil // v2.0
case 0x8:
return w | newFormat | memory256MB | sonyUK | bcm2835 | board1A | 2, nil // v2.0
case 0x9:
return w | newFormat | memory256MB | bcm2835 | board1A | 2, nil // v2.0 Qisda
case 0xd:
return w | newFormat | memory512MB | egoman | bcm2835 | board1B | 2, nil // v2.0
case 0xe:
return w | newFormat | memory512MB | sonyUK | bcm2835 | board1B | 2, nil // v2.0
case 0xf:
return w | newFormat | memory512MB | egoman | bcm2835 | board1B | 2, nil // v2.0
case 0x10:
return w | newFormat | memory512MB | sonyUK | bcm2835 | board1BPlus | 2, nil // v1.2
case 0x11:
return w | newFormat | memory512MB | sonyUK | bcm2835 | boardCM1, nil
case 0x12:
return w | newFormat | memory256MB | sonyUK | bcm2835 | board1APlus | 1, nil // v1.1
case 0x13:
return w | newFormat | memory512MB | embest | bcm2835 | board1BPlus | 2, nil // v1.2
case 0x14:
return w | newFormat | memory512MB | embest | bcm2835 | boardCM1, nil
case 0x15:
// Can be either 256MB or 512MB.
return w | newFormat | memory256MB | embest | bcm2835 | board1APlus | 1, nil // v1.1
default:
if v&uint32(newFormat) == 0 {
return 0, fmt.Errorf("rpi: unknown hardware version: 0x%x", v)
}
return revisionCode(v), nil
}
}
const (
warrantyVoid revisionCode = 1 << 24
newFormat revisionCode = 1 << 23
memoryShift = 20
memoryMask revisionCode = 0x7 << memoryShift
manufacturerShift = 16
manufacturerMask revisionCode = 0xf << manufacturerShift
processorShift = 12
processorMask revisionCode = 0xf << processorShift
boardShift = 4
boardMask revisionCode = 0xff << boardShift
revisionMask revisionCode = 0xf << 0
memory256MB revisionCode = 0 << memoryShift
memory512MB revisionCode = 1 << memoryShift
memory1GB revisionCode = 2 << memoryShift
memory2GB revisionCode = 3 << memoryShift
memory4GB revisionCode = 4 << memoryShift
sonyUK revisionCode = 0 << manufacturerShift
egoman revisionCode = 1 << manufacturerShift
embest revisionCode = 2 << manufacturerShift
sonyJapan revisionCode = 3 << manufacturerShift
embest2 revisionCode = 4 << manufacturerShift
stadium revisionCode = 5 << manufacturerShift
bcm2835 revisionCode = 0 << processorShift
bcm2836 revisionCode = 1 << processorShift
bcm2837 revisionCode = 2 << processorShift
bcm2711 revisionCode = 3 << processorShift
board1A revisionCode = 0x0 << boardShift
board1B revisionCode = 0x1 << boardShift
board1APlus revisionCode = 0x2 << boardShift
board1BPlus revisionCode = 0x3 << boardShift
board2B revisionCode = 0x4 << boardShift
boardAlpha revisionCode = 0x5 << boardShift
boardCM1 revisionCode = 0x6 << boardShift
board3B revisionCode = 0x8 << boardShift
boardZero revisionCode = 0x9 << boardShift
boardCM3 revisionCode = 0xa << boardShift
boardZeroW revisionCode = 0xc << boardShift
board3BPlus revisionCode = 0xd << boardShift
board3APlus revisionCode = 0xe << boardShift
boardReserved revisionCode = 0xf << boardShift
boardCM3Plus revisionCode = 0x10 << boardShift
board4B revisionCode = 0x11 << boardShift
)
// features represents the different features on various Raspberry Pi boards.
//
// See https://github.com/raspberrypi/firmware/blob/master/extra/dt-blob.dts
// for the official mapping.
type features struct {
hdrP1P26 bool // P1 has 26 pins
hdrP1P40 bool // P1 has 40 pins
hdrP5 bool // P5 is present
hdrAudio bool // Audio header is present
audioLeft41 bool // AUDIO_LEFT uses GPIO41 (RPi3 and later) instead of GPIO45 (old boards)
hdrHDMI bool // At least one HDMI port is present
hdrSODIMM bool // SODIMM port is present
}
func (f *features) init(v uint32) error {
r, err := parseRevision(v)
if err != nil {
return err
}
// Ignore the overclock bit.
r &^= warrantyVoid
switch r & boardMask {
case board1A:
f.hdrP1P26 = true
f.hdrAudio = true
// Only the v2 PCB has the P5 header.
if r&revisionMask == 2 {
f.hdrP5 = true
f.hdrHDMI = true
}
case board1B:
f.hdrP1P26 = true
f.hdrAudio = true
// Only the v2 PCB has the P5 header.
if r&revisionMask == 2 {
f.hdrP5 = true
f.hdrHDMI = true
}
case board1APlus:
f.hdrP1P40 = true
f.hdrAudio = true
f.hdrHDMI = true
case board1BPlus:
f.hdrP1P40 = true
f.hdrAudio = true
f.hdrHDMI = true
case board2B:
f.hdrP1P40 = true
f.hdrAudio = true
f.hdrHDMI = true
case boardAlpha:
case boardCM1:
// TODO: define CM1 SODIMM header if anyone ever needs it. Please file an
// issue at https://github.com/google/periph/issues/new/choose
case board3B:
f.hdrP1P40 = true
f.hdrAudio = true
f.audioLeft41 = true
f.hdrHDMI = true
case boardZero:
f.hdrP1P40 = true
f.hdrHDMI = true
case boardCM3:
// Tell CM3 and CM3-Lite apart, if possible.
f.hdrSODIMM = true
case boardZeroW:
f.hdrP1P40 = true
f.hdrHDMI = true
case board3BPlus:
f.hdrP1P40 = true
f.hdrAudio = true
f.audioLeft41 = true
f.hdrHDMI = true
case board3APlus:
f.hdrP1P40 = true
f.hdrAudio = true
f.audioLeft41 = true
f.hdrHDMI = true
case boardReserved:
case boardCM3Plus:
// Tell CM3 and CM3-Lite apart, if possible.
f.hdrSODIMM = true
case board4B:
f.hdrP1P40 = true
f.hdrAudio = true
f.audioLeft41 = true
f.hdrHDMI = true
default:
return fmt.Errorf("rpi: unknown hardware version: 0x%x", r)
}
return nil
}
// registerHeaders registers the headers for this board and fixes the GPIO
// global variables.
func (f *features) registerHeaders() error {
if f.hdrP1P26 {
if err := pinreg.Register("P1", [][]pin.Pin{
{P1_1, P1_2},
{P1_3, P1_4},
{P1_5, P1_6},
{P1_7, P1_8},
{P1_9, P1_10},
{P1_11, P1_12},
{P1_13, P1_14},
{P1_15, P1_16},
{P1_17, P1_18},
{P1_19, P1_20},
{P1_21, P1_22},
{P1_23, P1_24},
{P1_25, P1_26},
}); err != nil {
return err
}
// TODO(maruel): Models from 2012 and earlier have P1_3=GPIO0, P1_5=GPIO1 and P1_13=GPIO21.
// P2 and P3 are not useful.
// P6 has a RUN pin for reset but it's not available after Pi version 1.
P1_27 = gpio.INVALID
P1_28 = gpio.INVALID
P1_29 = gpio.INVALID
P1_30 = pin.INVALID
P1_31 = gpio.INVALID
P1_32 = gpio.INVALID
P1_33 = gpio.INVALID
P1_34 = pin.INVALID
P1_35 = gpio.INVALID
P1_36 = gpio.INVALID
P1_37 = gpio.INVALID
P1_38 = gpio.INVALID
P1_39 = pin.INVALID
P1_40 = gpio.INVALID
} else if f.hdrP1P40 {
if err := pinreg.Register("P1", [][]pin.Pin{
{P1_1, P1_2},
{P1_3, P1_4},
{P1_5, P1_6},
{P1_7, P1_8},
{P1_9, P1_10},
{P1_11, P1_12},
{P1_13, P1_14},
{P1_15, P1_16},
{P1_17, P1_18},
{P1_19, P1_20},
{P1_21, P1_22},
{P1_23, P1_24},
{P1_25, P1_26},
{P1_27, P1_28},
{P1_29, P1_30},
{P1_31, P1_32},
{P1_33, P1_34},
{P1_35, P1_36},
{P1_37, P1_38},
{P1_39, P1_40},
}); err != nil {
return err
}
} else {
P1_1 = pin.INVALID
P1_2 = pin.INVALID
P1_3 = gpio.INVALID
P1_4 = pin.INVALID
P1_5 = gpio.INVALID
P1_6 = pin.INVALID
P1_7 = gpio.INVALID
P1_8 = gpio.INVALID
P1_9 = pin.INVALID
P1_10 = gpio.INVALID
P1_11 = gpio.INVALID
P1_12 = gpio.INVALID
P1_13 = gpio.INVALID
P1_14 = pin.INVALID
P1_15 = gpio.INVALID
P1_16 = gpio.INVALID
P1_17 = pin.INVALID
P1_18 = gpio.INVALID
P1_19 = gpio.INVALID
P1_20 = pin.INVALID
P1_21 = gpio.INVALID
P1_22 = gpio.INVALID
P1_23 = gpio.INVALID
P1_24 = gpio.INVALID
P1_25 = pin.INVALID
P1_26 = gpio.INVALID
P1_27 = gpio.INVALID
P1_28 = gpio.INVALID
P1_29 = gpio.INVALID
P1_30 = pin.INVALID
P1_31 = gpio.INVALID
P1_32 = gpio.INVALID
P1_33 = gpio.INVALID
P1_34 = pin.INVALID
P1_35 = gpio.INVALID
P1_36 = gpio.INVALID
P1_37 = gpio.INVALID
P1_38 = gpio.INVALID
P1_39 = pin.INVALID
P1_40 = gpio.INVALID
}
// Only the A and B v2 PCB has the P5 header.
if f.hdrP5 {
if err := pinreg.Register("P5", [][]pin.Pin{
{P5_1, P5_2},
{P5_3, P5_4},
{P5_5, P5_6},
{P5_7, P5_8},
}); err != nil {
return err
}
} else {
P5_1 = pin.INVALID
P5_2 = pin.INVALID
P5_3 = gpio.INVALID
P5_4 = gpio.INVALID
P5_5 = gpio.INVALID
P5_6 = gpio.INVALID
P5_7 = pin.INVALID
P5_8 = pin.INVALID
}
if f.hdrSODIMM {
if err := pinreg.Register("SO", [][]pin.Pin{
{SO_1, SO_2},
{SO_3, SO_4},
{SO_5, SO_6},
{SO_7, SO_8},
{SO_9, SO_10},
{SO_11, SO_12},
{SO_13, SO_14},
{SO_15, SO_16},
{SO_17, SO_18},
{SO_19, SO_20},
{SO_21, SO_22},
{SO_23, SO_24},
{SO_25, SO_26},
{SO_27, SO_28},
{SO_29, SO_30},
{SO_31, SO_32},
{SO_33, SO_34},
{SO_35, SO_36},
{SO_37, SO_38},
{SO_39, SO_40},
{SO_41, SO_42},
{SO_43, SO_44},
{SO_45, SO_46},
{SO_47, SO_48},
{SO_49, SO_50},
{SO_51, SO_52},
{SO_53, SO_54},
{SO_55, SO_56},
{SO_57, SO_58},
{SO_59, SO_60},
{SO_61, SO_62},
{SO_63, SO_64},
{SO_65, SO_66},
{SO_67, SO_68},
{SO_69, SO_70},
{SO_71, SO_72},
{SO_73, SO_74},
{SO_75, SO_76},
{SO_77, SO_78},
{SO_79, SO_80},
{SO_81, SO_82},
{SO_83, SO_84},
{SO_85, SO_86},
{SO_87, SO_88},
{SO_89, SO_90},
{SO_91, SO_92},
{SO_93, SO_94},
{SO_95, SO_96},
{SO_97, SO_98},
{SO_99, SO_100},
{SO_101, SO_102},
{SO_103, SO_104},
{SO_105, SO_106},
{SO_107, SO_108},
{SO_109, SO_110},
{SO_111, SO_112},
{SO_113, SO_114},
{SO_115, SO_116},
{SO_117, SO_118},
{SO_119, SO_120},
{SO_121, SO_122},
{SO_123, SO_124},
{SO_125, SO_126},
{SO_127, SO_128},
{SO_129, SO_130},
{SO_131, SO_132},
{SO_133, SO_134},
{SO_135, SO_136},
{SO_137, SO_138},
{SO_139, SO_140},
{SO_141, SO_142},
{SO_143, SO_144},
{SO_145, SO_146},
{SO_147, SO_148},
{SO_149, SO_150},
{SO_151, SO_152},
{SO_153, SO_154},
{SO_155, SO_156},
{SO_157, SO_158},
{SO_159, SO_160},
{SO_161, SO_162},
{SO_163, SO_164},
{SO_165, SO_166},
{SO_167, SO_168},
{SO_169, SO_170},
{SO_171, SO_172},
{SO_173, SO_174},
{SO_175, SO_176},
{SO_177, SO_178},
{SO_179, SO_180},
{SO_181, SO_182},
{SO_183, SO_184},
{SO_185, SO_186},
{SO_187, SO_188},
{SO_189, SO_190},
{SO_191, SO_192},
{SO_193, SO_194},
{SO_195, SO_196},
{SO_197, SO_198},
{SO_199, SO_200},
}); err != nil {
return err
}
}
if f.hdrAudio {
// Two early versions of RPi1 had left and right reversed but we don't
// bother handling this here.
// https://github.com/raspberrypi/firmware/blob/master/extra/dt-blob.dts
if !f.audioLeft41 {
AUDIO_LEFT = bcm283x.GPIO45 // PWM1 for older boards
}
if err := pinreg.Register("AUDIO", [][]pin.Pin{
{AUDIO_LEFT},
{AUDIO_RIGHT},
}); err != nil {
return err
}
}
if f.hdrHDMI {
if err := pinreg.Register("HDMI", [][]pin.Pin{{HDMI_HOTPLUG_DETECT}}); err != nil {
return err
}
}
return nil
}
// driver implements periph.Driver.
type driver struct {
}
func (d *driver) String() string {
return "rpi"
}
func (d *driver) Prerequisites() []string {
return nil
}
func (d *driver) After() []string {
return []string{"bcm283x-gpio"}
}
func (d *driver) Init() (bool, error) {
if !Present() {
return false, errors.New("Raspberry Pi board not detected")
}
// Setup headers based on board revision.
//
// This code is not futureproof, it will error out on a Raspberry Pi 4
// whenever it comes out.
// Revision codes from: http://elinux.org/RPi_HardwareHistory
f := features{}
rev := distro.CPUInfo()["Revision"]
if v, err := strconv.ParseUint(rev, 16, 32); err == nil {
if err := f.init(uint32(v)); err != nil {
return true, err
}
} else {
return true, fmt.Errorf("rpi: failed to read cpu_info: %v", err)
}
return true, f.registerHeaders()
}
func init() {
if isArm {
periph.MustRegister(&drv)
}
}
var drv driver

7
vendor/periph.io/x/periph/host/rpi/rpi_arm.go generated vendored Normal file
View File

@ -0,0 +1,7 @@
// 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 rpi
const isArm = true

9
vendor/periph.io/x/periph/host/rpi/rpi_arm64.go generated vendored Normal file
View File

@ -0,0 +1,9 @@
// 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.
// +build arm64
package rpi
const isArm = true

9
vendor/periph.io/x/periph/host/rpi/rpi_other.go generated vendored Normal file
View File

@ -0,0 +1,9 @@
// 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.
// +build !arm,!arm64
package rpi
const isArm = false

13
vendor/periph.io/x/periph/host/sysfs/doc.go generated vendored Normal file
View File

@ -0,0 +1,13 @@
// 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 sysfs implements a sane library to interact with sysfs provided
// hardware access.
//
// sysfs a virtual file system rooted at /sys/.
//
// This package also include drivers using devfs.
//
// https://www.kernel.org/doc/Documentation/filesystems/sysfs.txt
package sysfs

317
vendor/periph.io/x/periph/host/sysfs/fs_linux.go generated vendored Normal file
View File

@ -0,0 +1,317 @@
// 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.
package sysfs
import (
"errors"
"os"
"strconv"
"strings"
"sync"
"sync/atomic"
"syscall"
"time"
)
// syscall.EpollCtl() commands.
//
// These are defined here so we don't need to import golang.org/x/sys/unix.
//
// http://man7.org/linux/man-pages/man2/epoll_ctl.2.html
const (
epollCTLAdd = 1 // EPOLL_CTL_ADD
epollCTLDel = 2 // EPOLL_CTL_DEL
epollCTLMod = 3 // EPOLL_CTL_MOD
)
// Bitmask for field syscall.EpollEvent.Events.
//
// These are defined here so we don't need to import golang.org/x/sys/unix.
//
// http://man7.org/linux/man-pages/man2/epoll_ctl.2.html
type epollEvent uint32
const (
epollIN epollEvent = 0x1 // EPOLLIN: available for read
epollOUT epollEvent = 0x4 // EPOLLOUT: available for write
epollPRI epollEvent = 0x2 // EPOLLPRI: exceptional urgent condition
epollERR epollEvent = 0x8 // EPOLLERR: error
epollHUP epollEvent = 0x10 // EPOLLHUP: hangup
epollET epollEvent = 0x80000000 // EPOLLET: Edge Triggered behavior
epollONESHOT epollEvent = 0x40000000 // EPOLLONESHOT: One shot
epollWAKEUP epollEvent = 0x20000000 // EPOLLWAKEUP: disable system sleep; kernel >=3.5
epollEXCLUSIVE epollEvent = 0x10000000 // EPOLLEXCLUSIVE: only wake one; kernel >=4.5
)
var bitmaskString = [...]struct {
e epollEvent
s string
}{
{epollIN, "IN"},
{epollOUT, "OUT"},
{epollPRI, "PRI"},
{epollERR, "ERR"},
{epollHUP, "HUP"},
{epollET, "ET"},
{epollONESHOT, "ONESHOT"},
{epollWAKEUP, "WAKEUP"},
{epollEXCLUSIVE, "EXCLUSIVE"},
}
// String is useful for debugging.
func (e epollEvent) String() string {
var out []string
for _, b := range bitmaskString {
if e&b.e != 0 {
out = append(out, b.s)
e &^= b.e
}
}
if e != 0 {
out = append(out, "0x"+strconv.FormatUint(uint64(e), 16))
}
if len(out) == 0 {
out = []string{"0"}
}
return strings.Join(out, "|")
}
// eventsListener listens for events for multiple files as a single system call.
//
// One OS thread is needed for all the events. This is more efficient on single
// core system.
type eventsListener struct {
// Atomic value set to one once fully initialized.
initialized int32
// Mapping of file descriptors to wait on with their corresponding channels.
mu sync.Mutex
// File descriptor of the epoll handle itself.
epollFd int
// Pipes to wake up the EpollWait() system call inside loop().
r, w *os.File
// Return channel to confirm that EpollWait() was woken up.
wakeUp <-chan time.Time
// Map of file handles to user listening channel.
fds map[int32]chan<- time.Time
}
// init must be called on a fresh instance.
func (e *eventsListener) init() error {
if atomic.LoadInt32(&e.initialized) != 0 {
// Was already initialized.
return nil
}
e.mu.Lock()
if atomic.LoadInt32(&e.initialized) != 0 {
// Was already initialized, but this was done concurrently with another
// thread.
e.mu.Unlock()
return nil
}
var err error
e.epollFd, err = syscall.EpollCreate(1)
switch {
case err == nil:
break
case err.Error() == "function not implemented":
// Some arch (arm64) do not implement EpollCreate().
if e.epollFd, err = syscall.EpollCreate1(0); err != nil {
e.mu.Unlock()
return err
}
default:
e.mu.Unlock()
return err
}
e.r, e.w, err = os.Pipe()
// Only need epollIN. epollPRI has no effect on pipes.
if err := e.addFdInner(e.r.Fd(), epollET|epollIN); err != nil {
// This object will not be reusable at this point.
e.mu.Unlock()
return err
}
wakeUp := make(chan time.Time)
e.wakeUp = wakeUp
e.fds = map[int32]chan<- time.Time{}
e.fds[int32(e.r.Fd())] = wakeUp
// The mutex is still held after this function exits, it's loop() that will
// release the mutex.
//
// This forces loop() to be started before addFd() can be called by users.
go e.loop()
// Initialization is now good to go.
atomic.StoreInt32(&e.initialized, 1)
return nil
}
// loop is the main event loop.
func (e *eventsListener) loop() {
var events []syscall.EpollEvent
type lookup struct {
c chan<- time.Time
event epollEvent
}
var lookups []lookup
for first := true; ; {
if !first {
e.mu.Lock()
}
if len(events) < len(e.fds) {
events = make([]syscall.EpollEvent, len(e.fds))
}
e.mu.Unlock()
first = false
if len(events) == 0 {
panic("internal error: there's should be at least one pipe")
}
// http://man7.org/linux/man-pages/man2/epoll_wait.2.html
n, err := syscall.EpollWait(e.epollFd, events, -1)
if n <= 0 {
// -1 if an error occurred (EBADF, EFAULT, EINVAL) or the call was
// interrupted by a signal (EINTR).
// 0 is the timeout occurred. In this case there's no timeout specified.
// Still handle this explicitly in case a timeout could be triggered by
// external events, like system sleep.
continue
}
if err != nil {
// TODO(maruel): It'd be nice to be able to surface this.
// This may cause a busy loop. Hopefully the user will notice and will
// fix their code.
// This can happen when removeFd() is called, in this case silently
// ignore the error.
continue
}
now := time.Now()
// Create a look up table with the lock, so that then the channel can be
// pushed to without the lock.
if cap(lookups) < n {
lookups = make([]lookup, 0, n)
} else {
lookups = lookups[:0]
}
e.mu.Lock()
for _, ev := range events[:n] {
ep := epollEvent(ev.Events)
// Skip over file descriptors that are not present.
c, ok := e.fds[ev.Fd]
if !ok {
// That's a race condition where the file descriptor was removed by
// removeFd() but it still triggered. Ignore this event.
continue
}
// Look at the event to determine if it's worth sending a pulse. It's
// maybe not worth it. Ignore epollERR, since it's always set for GPIO
// sysfs.
// Pipe and socket trigger epollIN and epollOUT, but GPIO sysfs triggers
// epollPRI.
if ep&(epollPRI|epollIN|epollOUT) != 0 {
lookups = append(lookups, lookup{c: c, event: ep})
}
}
e.mu.Unlock()
// Once the lock is released, send the timestamps.
for _, t := range lookups {
t.c <- now
}
}
}
// addFd starts listening to events generated by file descriptor |fd|.
//
// fd is the OS file descriptor. In practice, it must fit a int32 value. It
// works on pipes, sockets and sysfs objects like GPIO but not on standard
// files.
//
// c is the channel to send events to. Unbuffered channel will block the event
// loop, which may mean lost events, especially if multiple files are listened
// to simultaneously.
//
// flags is the events to listen to. No need to specify epollERR and epollHUP,
// they are sent anyway.
//
// addFd lazy initializes eventsListener if it was not initialized yet.
//
// It can fail due to various reasons, a few are:
// ENOSPC: /proc/sys/fs/epoll/max_user_watches limit was exceeded
// ENOMEM: No memory available
// EPERM: fd is a regular file or directory
func (e *eventsListener) addFd(fd uintptr, c chan<- time.Time, flags epollEvent) error {
if c == nil {
return errors.New("fd: addFd requires a valid channel")
}
if err := e.init(); err != nil {
return err
}
if err := e.addFdInner(fd, flags); err != nil {
return err
}
e.mu.Lock()
e.fds[int32(fd)] = c
e.mu.Unlock()
// Wake up the poller so it notices there's one new file.
e.wakeUpLoop(nil)
return nil
}
func (e *eventsListener) addFdInner(fd uintptr, flags epollEvent) error {
ev := syscall.EpollEvent{Events: uint32(flags), Fd: int32(fd)}
return syscall.EpollCtl(e.epollFd, epollCTLAdd, int(fd), &ev)
}
// removeFd stop listening to events on this file descriptor.
func (e *eventsListener) removeFd(fd uintptr) error {
if err := syscall.EpollCtl(e.epollFd, epollCTLDel, int(fd), nil); err != nil {
return err
}
e.mu.Lock()
delete(e.fds, int32(fd))
e.mu.Unlock()
// Wake up the poller so it notices there's one less file.
e.wakeUpLoop(nil)
return nil
}
// wakeUpLoop wakes up the poller and waits for it.
//
// Must not be called with the lock held.
func (e *eventsListener) wakeUpLoop(c <-chan time.Time) time.Time {
if atomic.LoadInt32(&e.initialized) == 0 {
return time.Time{}
}
// TODO(maruel): Figure out a way to wake up that doesn't require emptying.
var b [1]byte
_, _ = e.w.Write(b[:])
var t time.Time
if c != nil {
// To prevent deadlock, also empty c.
for {
select {
case <-c:
case t = <-e.wakeUp:
goto out
}
}
out:
} else {
t = <-e.wakeUp
}
// Don't forget to empty the pipe. Sadly, this will wake up the loop a second
// time.
_, _ = e.r.Read(b[:])
return t
}
// events is the global events listener.
//
// It uses a single global goroutine lazily initialized to call
// syscall.EpollWait() to listen to many file descriptors at once.
var events eventsListener

15
vendor/periph.io/x/periph/host/sysfs/fs_other.go generated vendored Normal file
View File

@ -0,0 +1,15 @@
// 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.
// +build !linux
package sysfs
type eventsListener struct {
}
// events is the global events listener.
//
// It is not used outside linux.
var events eventsListener

520
vendor/periph.io/x/periph/host/sysfs/gpio.go generated vendored Normal file
View File

@ -0,0 +1,520 @@
// 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 sysfs
import (
"errors"
"fmt"
"io"
"os"
"path/filepath"
"strconv"
"sync"
"time"
"periph.io/x/periph"
"periph.io/x/periph/conn"
"periph.io/x/periph/conn/gpio"
"periph.io/x/periph/conn/gpio/gpioreg"
"periph.io/x/periph/conn/physic"
"periph.io/x/periph/conn/pin"
"periph.io/x/periph/host/fs"
)
// Pins is all the pins exported by GPIO sysfs.
//
// Some CPU architectures have the pin numbers start at 0 and use consecutive
// pin numbers but this is not the case for all CPU architectures, some
// have gaps in the pin numbering.
//
// This global variable is initialized once at driver initialization and isn't
// mutated afterward. Do not modify it.
var Pins map[int]*Pin
// Pin represents one GPIO pin as found by sysfs.
type Pin struct {
number int
name string
root string // Something like /sys/class/gpio/gpio%d/
mu sync.Mutex
err error // If open() failed
direction direction // Cache of the last known direction
edge gpio.Edge // Cache of the last edge used.
fDirection fileIO // handle to /sys/class/gpio/gpio*/direction; never closed
fEdge fileIO // handle to /sys/class/gpio/gpio*/edge; never closed
fValue fileIO // handle to /sys/class/gpio/gpio*/value; never closed
event fs.Event // Initialized once
buf [4]byte // scratch buffer for Func(), Read() and Out()
}
// String implements conn.Resource.
func (p *Pin) String() string {
return p.name
}
// Halt implements conn.Resource.
//
// It stops edge detection if enabled.
func (p *Pin) Halt() error {
p.mu.Lock()
defer p.mu.Unlock()
return p.haltEdge()
}
// Name implements pin.Pin.
func (p *Pin) Name() string {
return p.name
}
// Number implements pin.Pin.
func (p *Pin) Number() int {
return p.number
}
// Function implements pin.Pin.
func (p *Pin) Function() string {
return string(p.Func())
}
// Func implements pin.PinFunc.
func (p *Pin) Func() pin.Func {
p.mu.Lock()
defer p.mu.Unlock()
// TODO(maruel): There's an internal bug which causes p.direction to be
// invalid (!?) Need to figure it out ASAP.
if err := p.open(); err != nil {
return pin.FuncNone
}
if _, err := seekRead(p.fDirection, p.buf[:]); err != nil {
return pin.FuncNone
}
if p.buf[0] == 'i' && p.buf[1] == 'n' {
p.direction = dIn
} else if p.buf[0] == 'o' && p.buf[1] == 'u' && p.buf[2] == 't' {
p.direction = dOut
}
if p.direction == dIn {
if p.Read() {
return gpio.IN_HIGH
}
return gpio.IN_LOW
} else if p.direction == dOut {
if p.Read() {
return gpio.OUT_HIGH
}
return gpio.OUT_LOW
}
return pin.FuncNone
}
// SupportedFuncs implements pin.PinFunc.
func (p *Pin) SupportedFuncs() []pin.Func {
return []pin.Func{gpio.IN, gpio.OUT}
}
// SetFunc implements pin.PinFunc.
func (p *Pin) SetFunc(f pin.Func) error {
switch f {
case gpio.IN:
return p.In(gpio.PullNoChange, gpio.NoEdge)
case gpio.OUT_HIGH:
return p.Out(gpio.High)
case gpio.OUT, gpio.OUT_LOW:
return p.Out(gpio.Low)
default:
return p.wrap(errors.New("unsupported function"))
}
}
// In implements gpio.PinIn.
func (p *Pin) In(pull gpio.Pull, edge gpio.Edge) error {
if pull != gpio.PullNoChange && pull != gpio.Float {
return p.wrap(errors.New("doesn't support pull-up/pull-down"))
}
p.mu.Lock()
defer p.mu.Unlock()
if p.direction != dIn {
if err := p.open(); err != nil {
return p.wrap(err)
}
if err := seekWrite(p.fDirection, bIn); err != nil {
return p.wrap(err)
}
p.direction = dIn
}
// Always push none to help accumulated flush edges. This is not fool proof
// but it seems to help.
if p.fEdge != nil {
if err := seekWrite(p.fEdge, bNone); err != nil {
return p.wrap(err)
}
}
// Assume that when the pin was switched, the driver doesn't recall if edge
// triggering was enabled.
if edge != gpio.NoEdge {
if p.fEdge == nil {
var err error
p.fEdge, err = fileIOOpen(p.root+"edge", os.O_RDWR)
if err != nil {
return p.wrap(err)
}
if err = p.event.MakeEvent(p.fValue.Fd()); err != nil {
_ = p.fEdge.Close()
p.fEdge = nil
return p.wrap(err)
}
}
// Always reset the edge detection mode to none after starting the epoll
// otherwise edges are not always delivered, as observed on an Allwinner A20
// running kernel 4.14.14.
if err := seekWrite(p.fEdge, bNone); err != nil {
return p.wrap(err)
}
var b []byte
switch edge {
case gpio.RisingEdge:
b = bRising
case gpio.FallingEdge:
b = bFalling
case gpio.BothEdges:
b = bBoth
}
if err := seekWrite(p.fEdge, b); err != nil {
return p.wrap(err)
}
}
p.edge = edge
// This helps to remove accumulated edges but this is not 100% sufficient.
// Most of the time the interrupts are handled promptly enough that this loop
// flushes the accumulated interrupt.
// Sometimes the kernel may have accumulated interrupts that haven't been
// processed for a long time, it can easily be >300µs even on a quite idle
// CPU. In this case, the loop below is not sufficient, since the interrupt
// will happen afterward "out of the blue".
if edge != gpio.NoEdge {
p.WaitForEdge(0)
}
return nil
}
// Read implements gpio.PinIn.
func (p *Pin) Read() gpio.Level {
// There's no lock here.
if p.fValue == nil {
return gpio.Low
}
if _, err := seekRead(p.fValue, p.buf[:]); err != nil {
// Error.
return gpio.Low
}
if p.buf[0] == '0' {
return gpio.Low
}
if p.buf[0] == '1' {
return gpio.High
}
// Error.
return gpio.Low
}
// WaitForEdge implements gpio.PinIn.
func (p *Pin) WaitForEdge(timeout time.Duration) bool {
// Run lockless, as the normal use is to call in a busy loop.
var ms int
if timeout == -1 {
ms = -1
} else {
ms = int(timeout / time.Millisecond)
}
start := time.Now()
for {
if nr, err := p.event.Wait(ms); err != nil {
return false
} else if nr == 1 {
// TODO(maruel): According to pigpio, the correct way to consume the
// interrupt is to call Seek().
return true
}
// A signal occurred.
if timeout != -1 {
ms = int((timeout - time.Since(start)) / time.Millisecond)
}
if ms <= 0 {
return false
}
}
}
// Pull implements gpio.PinIn.
//
// It returns gpio.PullNoChange since gpio sysfs has no support for input pull
// resistor.
func (p *Pin) Pull() gpio.Pull {
return gpio.PullNoChange
}
// DefaultPull implements gpio.PinIn.
//
// It returns gpio.PullNoChange since gpio sysfs has no support for input pull
// resistor.
func (p *Pin) DefaultPull() gpio.Pull {
return gpio.PullNoChange
}
// Out implements gpio.PinOut.
func (p *Pin) Out(l gpio.Level) error {
p.mu.Lock()
defer p.mu.Unlock()
if p.direction != dOut {
if err := p.open(); err != nil {
return p.wrap(err)
}
if err := p.haltEdge(); err != nil {
return err
}
// "To ensure glitch free operation, values "low" and "high" may be written
// to configure the GPIO as an output with that initial value."
var d []byte
if l == gpio.Low {
d = bLow
} else {
d = bHigh
}
if err := seekWrite(p.fDirection, d); err != nil {
return p.wrap(err)
}
p.direction = dOut
return nil
}
if l == gpio.Low {
p.buf[0] = '0'
} else {
p.buf[0] = '1'
}
if err := seekWrite(p.fValue, p.buf[:1]); err != nil {
return p.wrap(err)
}
return nil
}
// PWM implements gpio.PinOut.
//
// This is not supported on sysfs.
func (p *Pin) PWM(gpio.Duty, physic.Frequency) error {
return p.wrap(errors.New("pwm is not supported via sysfs"))
}
//
// open opens the gpio sysfs handle to /value and /direction.
//
// lock must be held.
func (p *Pin) open() error {
if p.fDirection != nil || p.err != nil {
return p.err
}
if drvGPIO.exportHandle == nil {
return errors.New("sysfs gpio is not initialized")
}
// Try to open the pin if it was there. It's possible it had been exported
// already.
if p.fValue, p.err = fileIOOpen(p.root+"value", os.O_RDWR); p.err == nil {
// Fast track.
goto direction
} else if !os.IsNotExist(p.err) {
// It exists but not accessible, not worth doing the remainder.
p.err = fmt.Errorf("need more access, try as root or setup udev rules: %v", p.err)
return p.err
}
if _, p.err = drvGPIO.exportHandle.Write([]byte(strconv.Itoa(p.number))); p.err != nil && !isErrBusy(p.err) {
if os.IsPermission(p.err) {
p.err = fmt.Errorf("need more access, try as root or setup udev rules: %v", p.err)
}
return p.err
}
// There's a race condition where the file may be created but udev is still
// running the Raspbian udev rule to make it readable to the current user.
// It's simpler to just loop a little as if /export is accessible, it doesn't
// make sense that gpioN/value doesn't become accessible eventually.
for start := time.Now(); time.Since(start) < 5*time.Second; {
// The virtual file creation is synchronous when writing to /export; albeit
// udev rule execution is asynchronous, so file mode change via udev rules
// takes some time to propagate.
if p.fValue, p.err = fileIOOpen(p.root+"value", os.O_RDWR); p.err == nil || !os.IsPermission(p.err) {
// Either success or a failure that is not a permission error.
break
}
}
if p.err != nil {
return p.err
}
direction:
if p.fDirection, p.err = fileIOOpen(p.root+"direction", os.O_RDWR); p.err != nil {
_ = p.fValue.Close()
p.fValue = nil
}
return p.err
}
// haltEdge stops any on-going edge detection.
func (p *Pin) haltEdge() error {
if p.edge != gpio.NoEdge {
if err := seekWrite(p.fEdge, bNone); err != nil {
return p.wrap(err)
}
p.edge = gpio.NoEdge
// This is still important to remove an accumulated edge.
p.WaitForEdge(0)
}
return nil
}
func (p *Pin) wrap(err error) error {
return fmt.Errorf("sysfs-gpio (%s): %v", p, err)
}
//
type direction int
const (
dUnknown direction = 0
dIn direction = 1
dOut direction = 2
)
var (
bIn = []byte("in")
bLow = []byte("low")
bHigh = []byte("high")
bNone = []byte("none")
bRising = []byte("rising")
bFalling = []byte("falling")
bBoth = []byte("both")
)
// readInt reads a pseudo-file (sysfs) that is known to contain an integer and
// returns the parsed number.
func readInt(path string) (int, error) {
f, err := fileIOOpen(path, os.O_RDONLY)
if err != nil {
return 0, err
}
defer f.Close()
var b [24]byte
n, err := f.Read(b[:])
if err != nil {
return 0, err
}
raw := b[:n]
if len(raw) == 0 || raw[len(raw)-1] != '\n' {
return 0, errors.New("invalid value")
}
return strconv.Atoi(string(raw[:len(raw)-1]))
}
// driverGPIO implements periph.Driver.
type driverGPIO struct {
exportHandle io.Writer // handle to /sys/class/gpio/export
}
func (d *driverGPIO) String() string {
return "sysfs-gpio"
}
func (d *driverGPIO) Prerequisites() []string {
return nil
}
func (d *driverGPIO) After() []string {
return nil
}
// Init initializes GPIO sysfs handling code.
//
// Uses gpio sysfs as described at
// https://www.kernel.org/doc/Documentation/gpio/sysfs.txt
//
// GPIO sysfs is often the only way to do edge triggered interrupts. Doing this
// requires cooperation from a driver in the kernel.
//
// The main drawback of GPIO sysfs is that it doesn't expose internal pull
// resistor and it is much slower than using memory mapped hardware registers.
func (d *driverGPIO) Init() (bool, error) {
items, err := filepath.Glob("/sys/class/gpio/gpiochip*")
if err != nil {
return true, err
}
if len(items) == 0 {
return false, errors.New("no GPIO pin found")
}
// There are hosts that use non-continuous pin numbering so use a map instead
// of an array.
Pins = map[int]*Pin{}
for _, item := range items {
if err := d.parseGPIOChip(item + "/"); err != nil {
return true, err
}
}
drvGPIO.exportHandle, err = fileIOOpen("/sys/class/gpio/export", os.O_WRONLY)
if os.IsPermission(err) {
return true, fmt.Errorf("need more access, try as root or setup udev rules: %v", err)
}
return true, err
}
func (d *driverGPIO) parseGPIOChip(path string) error {
base, err := readInt(path + "base")
if err != nil {
return err
}
number, err := readInt(path + "ngpio")
if err != nil {
return err
}
// TODO(maruel): The chip driver may lie and lists GPIO pins that cannot be
// exported. The only way to know about it is to export it before opening.
for i := base; i < base+number; i++ {
if _, ok := Pins[i]; ok {
return fmt.Errorf("found two pins with number %d", i)
}
p := &Pin{
number: i,
name: fmt.Sprintf("GPIO%d", i),
root: fmt.Sprintf("/sys/class/gpio/gpio%d/", i),
}
Pins[i] = p
if err := gpioreg.Register(p); err != nil {
return err
}
// If there is a CPU memory mapped gpio pin with the same number, the
// driver has to unregister this pin and map its own after.
if err := gpioreg.RegisterAlias(strconv.Itoa(i), p.name); err != nil {
return err
}
}
return nil
}
func init() {
if isLinux {
periph.MustRegister(&drvGPIO)
}
}
var drvGPIO driverGPIO
var _ conn.Resource = &Pin{}
var _ gpio.PinIn = &Pin{}
var _ gpio.PinOut = &Pin{}
var _ gpio.PinIO = &Pin{}
var _ pin.PinFunc = &Pin{}

388
vendor/periph.io/x/periph/host/sysfs/i2c.go generated vendored Normal file
View File

@ -0,0 +1,388 @@
// 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 sysfs
import (
"errors"
"fmt"
"os"
"path/filepath"
"sort"
"strconv"
"strings"
"sync"
"unsafe"
"periph.io/x/periph"
"periph.io/x/periph/conn/gpio"
"periph.io/x/periph/conn/gpio/gpioreg"
"periph.io/x/periph/conn/i2c"
"periph.io/x/periph/conn/i2c/i2creg"
"periph.io/x/periph/conn/physic"
)
// I2CSetSpeedHook can be set by a driver to enable changing the I²C buses
// speed.
func I2CSetSpeedHook(h func(f physic.Frequency) error) error {
if h == nil {
return errors.New("sysfs-i2c: hook must not be nil")
}
drvI2C.mu.Lock()
defer drvI2C.mu.Unlock()
if drvI2C.setSpeed != nil {
return errors.New("sysfs-i2c: a speed hook was already set")
}
drvI2C.setSpeed = h
return nil
}
// NewI2C opens an I²C bus via its sysfs interface as described at
// https://www.kernel.org/doc/Documentation/i2c/dev-interface.
//
// busNumber is the bus number as exported by sysfs. For example if the path is
// /dev/i2c-1, busNumber should be 1.
//
// The resulting object is safe for concurent use.
//
// Do not use sysfs.NewI2C() directly as the package sysfs is providing a
// https://periph.io/x/periph/conn/i2c Linux-specific implementation.
//
// periph.io works on many OSes!
//
// Instead, use https://periph.io/x/periph/conn/i2c/i2creg#Open. This permits
// it to work on all operating systems, or devices like I²C over USB.
func NewI2C(busNumber int) (*I2C, error) {
if isLinux {
return newI2C(busNumber)
}
return nil, errors.New("sysfs-i2c: is not supported on this platform")
}
// I2C is an open I²C bus via sysfs.
//
// It can be used to communicate with multiple devices from multiple goroutines.
type I2C struct {
f ioctlCloser
busNumber int
mu sync.Mutex // In theory the kernel probably has an internal lock but not taking any chance.
fn functionality
scl gpio.PinIO
sda gpio.PinIO
}
// Close closes the handle to the I²C driver. It is not a requirement to close
// before process termination.
func (i *I2C) Close() error {
i.mu.Lock()
defer i.mu.Unlock()
if err := i.f.Close(); err != nil {
return fmt.Errorf("sysfs-i2c: %v", err)
}
return nil
}
func (i *I2C) String() string {
return fmt.Sprintf("I2C%d", i.busNumber)
}
// Tx execute a transaction as a single operation unit.
func (i *I2C) Tx(addr uint16, w, r []byte) error {
if addr >= 0x400 || (addr >= 0x80 && i.fn&func10BitAddr == 0) {
return errors.New("sysfs-i2c: invalid address")
}
if len(w) == 0 && len(r) == 0 {
return nil
}
// Convert the messages to the internal format.
var buf [2]i2cMsg
msgs := buf[0:0]
if len(w) != 0 {
msgs = buf[:1]
buf[0].addr = addr
buf[0].length = uint16(len(w))
buf[0].buf = uintptr(unsafe.Pointer(&w[0]))
}
if len(r) != 0 {
l := len(msgs)
msgs = msgs[:l+1] // extend the slice by one
buf[l].addr = addr
buf[l].flags = flagRD
buf[l].length = uint16(len(r))
buf[l].buf = uintptr(unsafe.Pointer(&r[0]))
}
p := rdwrIoctlData{
msgs: uintptr(unsafe.Pointer(&msgs[0])),
nmsgs: uint32(len(msgs)),
}
pp := uintptr(unsafe.Pointer(&p))
i.mu.Lock()
defer i.mu.Unlock()
if err := i.f.Ioctl(ioctlRdwr, pp); err != nil {
return fmt.Errorf("sysfs-i2c: %v", err)
}
return nil
}
// SetSpeed implements i2c.Bus.
func (i *I2C) SetSpeed(f physic.Frequency) error {
if f > 100*physic.MegaHertz {
return fmt.Errorf("sysfs-i2c: invalid speed %s; maximum supported clock is 100MHz", f)
}
if f < physic.KiloHertz {
return fmt.Errorf("sysfs-i2c: invalid speed %s; minimum supported clock is 1KHz; did you forget to multiply by physic.KiloHertz?", f)
}
drvI2C.mu.Lock()
defer drvI2C.mu.Unlock()
if drvI2C.setSpeed != nil {
return drvI2C.setSpeed(f)
}
return errors.New("sysfs-i2c: not supported")
}
// SCL implements i2c.Pins.
func (i *I2C) SCL() gpio.PinIO {
i.initPins()
return i.scl
}
// SDA implements i2c.Pins.
func (i *I2C) SDA() gpio.PinIO {
i.initPins()
return i.sda
}
// Private details.
func newI2C(busNumber int) (*I2C, error) {
// Use the devfs path for now instead of sysfs path.
f, err := ioctlOpen(fmt.Sprintf("/dev/i2c-%d", busNumber), os.O_RDWR)
if err != nil {
// Try to be helpful here. There are generally two cases:
// - /dev/i2c-X doesn't exist. In this case, /boot/config.txt has to be
// edited to enable I²C then the device must be rebooted.
// - permission denied. In this case, the user has to be added to plugdev.
if os.IsNotExist(err) {
return nil, fmt.Errorf("sysfs-i2c: bus #%d is not configured: %v", busNumber, err)
}
// TODO(maruel): This is a debianism.
return nil, fmt.Errorf("sysfs-i2c: are you member of group 'plugdev'? %v", err)
}
i := &I2C{f: f, busNumber: busNumber}
// TODO(maruel): Changing the speed is currently doing this for all devices.
// https://github.com/raspberrypi/linux/issues/215
// Need to access /sys/module/i2c_bcm2708/parameters/baudrate
// Query to know if 10 bits addresses are supported.
if err = i.f.Ioctl(ioctlFuncs, uintptr(unsafe.Pointer(&i.fn))); err != nil {
return nil, fmt.Errorf("sysfs-i2c: %v", err)
}
return i, nil
}
func (i *I2C) initPins() {
i.mu.Lock()
if i.scl == nil {
if i.scl = gpioreg.ByName(fmt.Sprintf("I2C%d_SCL", i.busNumber)); i.scl == nil {
i.scl = gpio.INVALID
}
if i.sda = gpioreg.ByName(fmt.Sprintf("I2C%d_SDA", i.busNumber)); i.sda == nil {
i.sda = gpio.INVALID
}
}
i.mu.Unlock()
}
// i2cdev driver IOCTL control codes.
//
// Constants and structure definition can be found at
// /usr/include/linux/i2c-dev.h and /usr/include/linux/i2c.h.
const (
ioctlRetries = 0x701 // TODO(maruel): Expose this
ioctlTimeout = 0x702 // TODO(maruel): Expose this; in units of 10ms
ioctlSlave = 0x703
ioctlTenBits = 0x704 // TODO(maruel): Expose this but the header says it's broken (!?)
ioctlFuncs = 0x705
ioctlRdwr = 0x707
)
// flags
const (
flagTEN = 0x0010 // this is a ten bit chip address
flagRD = 0x0001 // read data, from slave to master
flagSTOP = 0x8000 // if funcProtocolMangling
flagNOSTART = 0x4000 // if I2C_FUNC_NOSTART
flagRevDirAddr = 0x2000 // if funcProtocolMangling
flagIgnoreNAK = 0x1000 // if funcProtocolMangling
flagNoRDACK = 0x0800 // if funcProtocolMangling
flagRecvLen = 0x0400 // length will be first received byte
)
type functionality uint64
const (
funcI2C = 0x00000001
func10BitAddr = 0x00000002
funcProtocolMangling = 0x00000004 // I2C_M_IGNORE_NAK etc.
funcSMBusPEC = 0x00000008
funcNOSTART = 0x00000010 // I2C_M_NOSTART
funcSMBusBlockProcCall = 0x00008000 // SMBus 2.0
funcSMBusQuick = 0x00010000
funcSMBusReadByte = 0x00020000
funcSMBusWriteByte = 0x00040000
funcSMBusReadByteData = 0x00080000
funcSMBusWriteByteData = 0x00100000
funcSMBusReadWordData = 0x00200000
funcSMBusWriteWordData = 0x00400000
funcSMBusProcCall = 0x00800000
funcSMBusReadBlockData = 0x01000000
funcSMBusWriteBlockData = 0x02000000
funcSMBusReadI2CBlock = 0x04000000 // I2C-like block xfer
funcSMBusWriteI2CBlock = 0x08000000 // w/ 1-byte reg. addr.
)
func (f functionality) String() string {
var out []string
if f&funcI2C != 0 {
out = append(out, "I2C")
}
if f&func10BitAddr != 0 {
out = append(out, "10BIT_ADDR")
}
if f&funcProtocolMangling != 0 {
out = append(out, "PROTOCOL_MANGLING")
}
if f&funcSMBusPEC != 0 {
out = append(out, "SMBUS_PEC")
}
if f&funcNOSTART != 0 {
out = append(out, "NOSTART")
}
if f&funcSMBusBlockProcCall != 0 {
out = append(out, "SMBUS_BLOCK_PROC_CALL")
}
if f&funcSMBusQuick != 0 {
out = append(out, "SMBUS_QUICK")
}
if f&funcSMBusReadByte != 0 {
out = append(out, "SMBUS_READ_BYTE")
}
if f&funcSMBusWriteByte != 0 {
out = append(out, "SMBUS_WRITE_BYTE")
}
if f&funcSMBusReadByteData != 0 {
out = append(out, "SMBUS_READ_BYTE_DATA")
}
if f&funcSMBusWriteByteData != 0 {
out = append(out, "SMBUS_WRITE_BYTE_DATA")
}
if f&funcSMBusReadWordData != 0 {
out = append(out, "SMBUS_READ_WORD_DATA")
}
if f&funcSMBusWriteWordData != 0 {
out = append(out, "SMBUS_WRITE_WORD_DATA")
}
if f&funcSMBusProcCall != 0 {
out = append(out, "SMBUS_PROC_CALL")
}
if f&funcSMBusReadBlockData != 0 {
out = append(out, "SMBUS_READ_BLOCK_DATA")
}
if f&funcSMBusWriteBlockData != 0 {
out = append(out, "SMBUS_WRITE_BLOCK_DATA")
}
if f&funcSMBusReadI2CBlock != 0 {
out = append(out, "SMBUS_READ_I2C_BLOCK")
}
if f&funcSMBusWriteI2CBlock != 0 {
out = append(out, "SMBUS_WRITE_I2C_BLOCK")
}
return strings.Join(out, "|")
}
type rdwrIoctlData struct {
msgs uintptr // Pointer to i2cMsg
nmsgs uint32
}
type i2cMsg struct {
addr uint16 // Address to communicate with
flags uint16 // 1 for read, see i2c.h for more details
length uint16
buf uintptr
}
//
// driverI2C implements periph.Driver.
type driverI2C struct {
mu sync.Mutex
buses []string
setSpeed func(f physic.Frequency) error
}
func (d *driverI2C) String() string {
return "sysfs-i2c"
}
func (d *driverI2C) Prerequisites() []string {
return nil
}
func (d *driverI2C) After() []string {
return nil
}
func (d *driverI2C) Init() (bool, error) {
// Do not use "/sys/bus/i2c/devices/i2c-" as Raspbian's provided udev rules
// only modify the ACL of /dev/i2c-* but not the ones in /sys/bus/...
prefix := "/dev/i2c-"
items, err := filepath.Glob(prefix + "*")
if err != nil {
return true, err
}
if len(items) == 0 {
return false, errors.New("no I²C bus found")
}
// Make sure they are registered in order.
sort.Strings(items)
for _, item := range items {
bus, err := strconv.Atoi(item[len(prefix):])
if err != nil {
continue
}
name := fmt.Sprintf("/dev/i2c-%d", bus)
d.buses = append(d.buses, name)
aliases := []string{fmt.Sprintf("I2C%d", bus)}
if err := i2creg.Register(name, aliases, bus, openerI2C(bus).Open); err != nil {
return true, err
}
}
return true, nil
}
type openerI2C int
func (o openerI2C) Open() (i2c.BusCloser, error) {
b, err := NewI2C(int(o))
if err != nil {
return nil, err
}
return b, nil
}
func init() {
if isLinux {
periph.MustRegister(&drvI2C)
}
}
var drvI2C driverI2C
var _ i2c.Bus = &I2C{}
var _ i2c.BusCloser = &I2C{}

257
vendor/periph.io/x/periph/host/sysfs/led.go generated vendored Normal file
View File

@ -0,0 +1,257 @@
// 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 sysfs
import (
"errors"
"fmt"
"os"
"path/filepath"
"sort"
"strconv"
"sync"
"time"
"periph.io/x/periph"
"periph.io/x/periph/conn"
"periph.io/x/periph/conn/gpio"
"periph.io/x/periph/conn/physic"
"periph.io/x/periph/conn/pin"
"periph.io/x/periph/host/fs"
)
// LEDs is all the leds discovered on this host via sysfs.
//
// Depending on the user context, the LEDs may be read-only or writeable.
var LEDs []*LED
// LEDByName returns a *LED for the LED name, if any.
//
// For all practical purpose, a LED is considered an output-only gpio.PinOut.
func LEDByName(name string) (*LED, error) {
// TODO(maruel): Use a bisect or a map. For now we don't expect more than a
// handful of LEDs so it doesn't matter.
for _, led := range LEDs {
if led.name == name {
if err := led.open(); err != nil {
return nil, err
}
return led, nil
}
}
return nil, errors.New("sysfs-led: invalid LED name")
}
// LED represents one LED on the system.
type LED struct {
number int
name string
root string
mu sync.Mutex
fBrightness *fs.File // handle to /sys/class/gpio/gpio*/direction; never closed
}
// String implements conn.Resource.
func (l *LED) String() string {
return fmt.Sprintf("%s(%d)", l.name, l.number)
}
// Halt implements conn.Resource.
//
// It turns the light off.
func (l *LED) Halt() error {
return l.Out(gpio.Low)
}
// Name implements pin.Pin.
func (l *LED) Name() string {
return l.name
}
// Number implements pin.Pin.
func (l *LED) Number() int {
return l.number
}
// Function implements pin.Pin.
func (l *LED) Function() string {
return string(l.Func())
}
// Func implements pin.PinFunc.
func (l *LED) Func() pin.Func {
if l.Read() {
return "LED/On"
}
return "LED/Off"
}
// SupportedFuncs implements pin.PinFunc.
func (l *LED) SupportedFuncs() []pin.Func {
return []pin.Func{"LED"}
}
// SetFunc implements pin.PinFunc.
func (l *LED) SetFunc(f pin.Func) error {
return errors.New("sysfs-led: not implemented")
}
// In implements gpio.PinIn.
func (l *LED) In(pull gpio.Pull, edge gpio.Edge) error {
if pull != gpio.Float && pull != gpio.PullNoChange {
return errors.New("sysfs-led: pull is not supported on LED")
}
if edge != gpio.NoEdge {
return errors.New("sysfs-led: edge is not supported on LED")
}
return nil
}
// Read implements gpio.PinIn.
func (l *LED) Read() gpio.Level {
err := l.open()
if err != nil {
return gpio.Low
}
l.mu.Lock()
defer l.mu.Unlock()
if _, err := l.fBrightness.Seek(0, 0); err != nil {
return gpio.Low
}
var b [4]byte
if _, err := l.fBrightness.Read(b[:]); err != nil {
return gpio.Low
}
if b[0] != '0' {
return gpio.High
}
return gpio.Low
}
// WaitForEdge implements gpio.PinIn.
func (l *LED) WaitForEdge(timeout time.Duration) bool {
return false
}
// Pull implements gpio.PinIn.
func (l *LED) Pull() gpio.Pull {
return gpio.PullNoChange
}
// DefaultPull implements gpio.PinIn.
func (l *LED) DefaultPull() gpio.Pull {
return gpio.PullNoChange
}
// Out implements gpio.PinOut.
func (l *LED) Out(level gpio.Level) error {
err := l.open()
if err != nil {
return err
}
l.mu.Lock()
defer l.mu.Unlock()
if _, err = l.fBrightness.Seek(0, 0); err != nil {
return err
}
if level {
_, err = l.fBrightness.Write([]byte("255"))
} else {
_, err = l.fBrightness.Write([]byte("0"))
}
return err
}
// PWM implements gpio.PinOut.
//
// This sets the intensity level, if supported. The frequency is ignored.
func (l *LED) PWM(d gpio.Duty, f physic.Frequency) error {
err := l.open()
if err != nil {
return err
}
l.mu.Lock()
defer l.mu.Unlock()
if _, err = l.fBrightness.Seek(0, 0); err != nil {
return err
}
v := (d + gpio.DutyMax/512) / (gpio.DutyMax / 256)
_, err = l.fBrightness.Write([]byte(strconv.Itoa(int(v))))
return err
}
//
func (l *LED) open() error {
l.mu.Lock()
defer l.mu.Unlock()
// trigger, max_brightness.
var err error
if l.fBrightness == nil {
p := l.root + "brightness"
if l.fBrightness, err = fs.Open(p, os.O_RDWR); err != nil {
// Retry with read-only. This is the default setting.
l.fBrightness, err = fs.Open(p, os.O_RDONLY)
}
}
return err
}
// driverLED implements periph.Driver.
type driverLED struct {
}
func (d *driverLED) String() string {
return "sysfs-led"
}
func (d *driverLED) Prerequisites() []string {
return nil
}
func (d *driverLED) After() []string {
return nil
}
// Init initializes LEDs sysfs handling code.
//
// Uses led sysfs as described* at
// https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-class-led
//
// * for the most minimalistic meaning of 'described'.
func (d *driverLED) Init() (bool, error) {
items, err := filepath.Glob("/sys/class/leds/*")
if err != nil {
return true, err
}
if len(items) == 0 {
return false, errors.New("no LED found")
}
// This make the LEDs in deterministic order.
sort.Strings(items)
for i, item := range items {
LEDs = append(LEDs, &LED{
number: i,
name: filepath.Base(item),
root: item + "/",
})
}
return true, nil
}
func init() {
if isLinux {
periph.MustRegister(&drvLED)
}
}
var drvLED driverLED
var _ conn.Resource = &LED{}
var _ gpio.PinIn = &LED{}
var _ gpio.PinOut = &LED{}
var _ gpio.PinIO = &LED{}
var _ pin.PinFunc = &LED{}

622
vendor/periph.io/x/periph/host/sysfs/spi.go generated vendored Normal file
View File

@ -0,0 +1,622 @@
// 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 sysfs
import (
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"sort"
"strconv"
"strings"
"sync"
"unsafe"
"periph.io/x/periph"
"periph.io/x/periph/conn"
"periph.io/x/periph/conn/gpio"
"periph.io/x/periph/conn/gpio/gpioreg"
"periph.io/x/periph/conn/physic"
"periph.io/x/periph/conn/spi"
"periph.io/x/periph/conn/spi/spireg"
"periph.io/x/periph/host/fs"
)
// NewSPI opens a SPI port via its devfs interface as described at
// https://www.kernel.org/doc/Documentation/spi/spidev and
// https://www.kernel.org/doc/Documentation/spi/spi-summary
//
// The resulting object is safe for concurrent use.
//
// busNumber is the bus number as exported by devfs. For example if the path is
// /dev/spidev0.1, busNumber should be 0 and chipSelect should be 1.
//
// It is recommended to use https://periph.io/x/periph/conn/spi/spireg#Open
// instead of using NewSPI() directly as the package sysfs is providing a
// Linux-specific implementation. periph.io works on many OSes! This permits
// it to work on all operating systems, or devices like SPI over USB.
func NewSPI(busNumber, chipSelect int) (*SPI, error) {
if isLinux {
return newSPI(busNumber, chipSelect)
}
return nil, errors.New("sysfs-spi: not implemented on non-linux OSes")
}
// SPI is an open SPI port.
type SPI struct {
conn spiConn
}
// Close closes the handle to the SPI driver. It is not a requirement to close
// before process termination.
//
// Note that the object is not reusable afterward.
func (s *SPI) Close() error {
s.conn.mu.Lock()
defer s.conn.mu.Unlock()
if err := s.conn.f.Close(); err != nil {
return fmt.Errorf("sysfs-spi: %v", err)
}
s.conn.f = nil
return nil
}
func (s *SPI) String() string {
return s.conn.String()
}
// LimitSpeed implements spi.ConnCloser.
func (s *SPI) LimitSpeed(f physic.Frequency) error {
if f > physic.GigaHertz {
return fmt.Errorf("sysfs-spi: invalid speed %s; maximum supported clock is 1GHz", f)
}
if f < 100*physic.Hertz {
return fmt.Errorf("sysfs-spi: invalid speed %s; minimum supported clock is 100Hz; did you forget to multiply by physic.MegaHertz?", f)
}
s.conn.mu.Lock()
defer s.conn.mu.Unlock()
s.conn.freqPort = f
return nil
}
// Connect implements spi.Port.
//
// It must be called before any I/O.
func (s *SPI) Connect(f physic.Frequency, mode spi.Mode, bits int) (spi.Conn, error) {
if f > physic.GigaHertz {
return nil, fmt.Errorf("sysfs-spi: invalid speed %s; maximum supported clock is 1GHz", f)
}
if f < 100*physic.Hertz {
return nil, fmt.Errorf("sysfs-spi: invalid speed %s; minimum supported clock is 100Hz; did you forget to multiply by physic.MegaHertz?", f)
}
if mode&^(spi.Mode3|spi.HalfDuplex|spi.NoCS|spi.LSBFirst) != 0 {
return nil, fmt.Errorf("sysfs-spi: invalid mode %v", mode)
}
if bits < 1 || bits >= 256 {
return nil, fmt.Errorf("sysfs-spi: invalid bits %d", bits)
}
s.conn.mu.Lock()
defer s.conn.mu.Unlock()
if s.conn.connected {
return nil, errors.New("sysfs-spi: Connect() can only be called exactly once")
}
s.conn.connected = true
s.conn.freqConn = f
s.conn.bitsPerWord = uint8(bits)
// Only mode needs to be set via an IOCTL, others can be specified in the
// spiIOCTransfer packet, which saves a kernel call.
m := mode & spi.Mode3
s.conn.muPins.Lock()
{
if mode&spi.HalfDuplex != 0 {
m |= threeWire
s.conn.halfDuplex = true
// In case initPins() had been called before Connect().
s.conn.mosi = gpio.INVALID
}
if mode&spi.NoCS != 0 {
m |= noCS
s.conn.noCS = true
// In case initPins() had been called before Connect().
s.conn.cs = gpio.INVALID
}
}
s.conn.muPins.Unlock()
if mode&spi.LSBFirst != 0 {
m |= lSBFirst
}
// Only the first 8 bits are used. This only works because the system is
// running in little endian.
if err := s.conn.setFlag(spiIOCMode, uint64(m)); err != nil {
return nil, fmt.Errorf("sysfs-spi: setting mode %v failed: %v", mode, err)
}
return &s.conn, nil
}
// MaxTxSize implements conn.Limits
func (s *SPI) MaxTxSize() int {
return drvSPI.bufSize
}
// CLK implements spi.Pins.
func (s *SPI) CLK() gpio.PinOut {
return s.conn.CLK()
}
// MISO implements spi.Pins.
func (s *SPI) MISO() gpio.PinIn {
return s.conn.MISO()
}
// MOSI implements spi.Pins.
func (s *SPI) MOSI() gpio.PinOut {
return s.conn.MOSI()
}
// CS implements spi.Pins.
func (s *SPI) CS() gpio.PinOut {
return s.conn.CS()
}
// Private details.
func newSPI(busNumber, chipSelect int) (*SPI, error) {
if busNumber < 0 || busNumber >= 1<<16 {
return nil, fmt.Errorf("sysfs-spi: invalid bus %d", busNumber)
}
if chipSelect < 0 || chipSelect > 255 {
return nil, fmt.Errorf("sysfs-spi: invalid chip select %d", chipSelect)
}
// Use the devfs path for now.
f, err := ioctlOpen(fmt.Sprintf("/dev/spidev%d.%d", busNumber, chipSelect), os.O_RDWR)
if err != nil {
return nil, fmt.Errorf("sysfs-spi: %v", err)
}
return &SPI{
spiConn{
name: fmt.Sprintf("SPI%d.%d", busNumber, chipSelect),
f: f,
busNumber: busNumber,
chipSelect: chipSelect,
},
}, nil
}
//
// spiConn implements spi.Conn.
type spiConn struct {
// Immutable
name string
f ioctlCloser
busNumber int
chipSelect int
mu sync.Mutex
freqPort physic.Frequency // Frequency specified at LimitSpeed()
freqConn physic.Frequency // Frequency specified at Connect()
bitsPerWord uint8
connected bool
halfDuplex bool
noCS bool
// Heap optimization: reduce the amount of memory allocations during
// transactions.
io [4]spiIOCTransfer
p [2]spi.Packet
// Use a separate lock for the pins, so that they can be queried while a
// transaction is happening.
muPins sync.Mutex
clk gpio.PinOut
mosi gpio.PinOut
miso gpio.PinIn
cs gpio.PinOut
}
func (s *spiConn) String() string {
return s.name
}
// Read implements io.Reader.
func (s *spiConn) Read(b []byte) (int, error) {
if len(b) == 0 {
return 0, errors.New("sysfs-spi: Read() with empty buffer")
}
if drvSPI.bufSize != 0 && len(b) > drvSPI.bufSize {
return 0, fmt.Errorf("sysfs-spi: maximum Read length is %d, got %d bytes", drvSPI.bufSize, len(b))
}
s.mu.Lock()
defer s.mu.Unlock()
s.p[0].W = nil
s.p[0].R = b
if err := s.txPackets(s.p[:1]); err != nil {
return 0, fmt.Errorf("sysfs-spi: Read() failed: %v", err)
}
return len(b), nil
}
// Write implements io.Writer.
func (s *spiConn) Write(b []byte) (int, error) {
if len(b) == 0 {
return 0, errors.New("sysfs-spi: Write() with empty buffer")
}
if drvSPI.bufSize != 0 && len(b) > drvSPI.bufSize {
return 0, fmt.Errorf("sysfs-spi: maximum Write length is %d, got %d bytes", drvSPI.bufSize, len(b))
}
s.mu.Lock()
defer s.mu.Unlock()
s.p[0].W = b
s.p[0].R = nil
if err := s.txPackets(s.p[:1]); err != nil {
return 0, fmt.Errorf("sysfs-spi: Write() failed: %v", err)
}
return len(b), nil
}
// Tx sends and receives data simultaneously.
//
// It is OK if both w and r point to the same underlying byte slice.
//
// spidev enforces the maximum limit of transaction size. It can be as low as
// 4096 bytes. See the platform documentation to learn how to increase the
// limit.
func (s *spiConn) Tx(w, r []byte) error {
l := len(w)
if l == 0 {
if l = len(r); l == 0 {
return errors.New("sysfs-spi: Tx() with empty buffers")
}
} else {
// It's not a big deal to read halfDuplex without the lock.
if !s.halfDuplex && len(r) != 0 && len(r) != len(w) {
return fmt.Errorf("sysfs-spi: Tx(): when both w and r are used, they must be the same size; got %d and %d bytes", len(w), len(r))
}
}
if drvSPI.bufSize != 0 && l > drvSPI.bufSize {
return fmt.Errorf("sysfs-spi: maximum Tx length is %d, got %d bytes", drvSPI.bufSize, l)
}
s.mu.Lock()
defer s.mu.Unlock()
s.p[0].W = w
s.p[0].R = r
p := s.p[:1]
if s.halfDuplex && len(w) != 0 && len(r) != 0 {
// Create two packets for HalfDuplex operation: one write then one read.
s.p[0].R = nil
s.p[0].KeepCS = true
s.p[1].W = nil
s.p[1].R = r
s.p[1].KeepCS = false
p = s.p[:2]
} else {
s.p[0].KeepCS = false
}
if err := s.txPackets(p); err != nil {
return fmt.Errorf("sysfs-spi: Tx() failed: %v", err)
}
return nil
}
// TxPackets sends and receives packets as specified by the user.
//
// spidev enforces the maximum limit of transaction size. It can be as low as
// 4096 bytes. See the platform documentation to learn how to increase the
// limit.
func (s *spiConn) TxPackets(p []spi.Packet) error {
total := 0
for i := range p {
lW := len(p[i].W)
lR := len(p[i].R)
if lW != lR && lW != 0 && lR != 0 {
return fmt.Errorf("sysfs-spi: when both w and r are used, they must be the same size; got %d and %d bytes", lW, lR)
}
l := lW
if l == 0 {
l = lR
}
total += l
}
if total == 0 {
return errors.New("sysfs-spi: empty packets")
}
if drvSPI.bufSize != 0 && total > drvSPI.bufSize {
return fmt.Errorf("sysfs-spi: maximum TxPackets length is %d, got %d bytes", drvSPI.bufSize, total)
}
s.mu.Lock()
defer s.mu.Unlock()
if s.halfDuplex {
for i := range p {
if len(p[i].W) != 0 && len(p[i].R) != 0 {
return errors.New("sysfs-spi: can only specify one of w or r when in half duplex")
}
}
}
if err := s.txPackets(p); err != nil {
return fmt.Errorf("sysfs-spi: TxPackets() failed: %v", err)
}
return nil
}
// Duplex implements conn.Conn.
func (s *spiConn) Duplex() conn.Duplex {
if s.halfDuplex {
return conn.Half
}
return conn.Full
}
// MaxTxSize implements conn.Limits.
func (s *spiConn) MaxTxSize() int {
return drvSPI.bufSize
}
// CLK implements spi.Pins.
func (s *spiConn) CLK() gpio.PinOut {
s.initPins()
return s.clk
}
// MISO implements spi.Pins.
func (s *spiConn) MISO() gpio.PinIn {
s.initPins()
return s.miso
}
// MOSI implements spi.Pins.
func (s *spiConn) MOSI() gpio.PinOut {
s.initPins()
return s.mosi
}
// CS implements spi.Pins.
func (s *spiConn) CS() gpio.PinOut {
s.initPins()
return s.cs
}
//
func (s *spiConn) txPackets(p []spi.Packet) error {
// Convert the packets.
f := s.freqPort
if s.freqConn != 0 && (s.freqPort == 0 || s.freqConn < s.freqPort) {
f = s.freqConn
}
var m []spiIOCTransfer
if len(p) > len(s.io) {
m = make([]spiIOCTransfer, len(p))
} else {
m = s.io[:len(p)]
}
for i := range p {
bits := p[i].BitsPerWord
if bits == 0 {
bits = s.bitsPerWord
}
csInvert := false
if !s.noCS {
// Invert CS behavior when a packet has KeepCS false, except for the last
// packet when KeepCS is true.
last := i == len(p)-1
csInvert = p[i].KeepCS == last
}
m[i].reset(p[i].W, p[i].R, f, bits, csInvert)
}
return s.f.Ioctl(spiIOCTx(len(m)), uintptr(unsafe.Pointer(&m[0])))
}
func (s *spiConn) setFlag(op uint, arg uint64) error {
return s.f.Ioctl(op, uintptr(unsafe.Pointer(&arg)))
}
// GetFlag allows to read back flags set via a ioctl, i.e. setFlag. It is
// exported to allow calling it from the smoke test.
func (s *spiConn) GetFlag(op uint) (arg uint64, err error) {
err = s.f.Ioctl(op, uintptr(unsafe.Pointer(&arg)))
return
}
func (s *spiConn) initPins() {
s.muPins.Lock()
defer s.muPins.Unlock()
if s.clk != nil {
return
}
if s.clk = gpioreg.ByName(fmt.Sprintf("SPI%d_CLK", s.busNumber)); s.clk == nil {
s.clk = gpio.INVALID
}
if s.miso = gpioreg.ByName(fmt.Sprintf("SPI%d_MISO", s.busNumber)); s.miso == nil {
s.miso = gpio.INVALID
}
// s.mosi is set to INVALID if HalfDuplex was specified.
if s.mosi != gpio.INVALID {
if s.mosi = gpioreg.ByName(fmt.Sprintf("SPI%d_MOSI", s.busNumber)); s.mosi == nil {
s.mosi = gpio.INVALID
}
}
// s.cs is set to INVALID if NoCS was specified.
if s.cs != gpio.INVALID {
if s.cs = gpioreg.ByName(fmt.Sprintf("SPI%d_CS%d", s.busNumber, s.chipSelect)); s.cs == nil {
s.cs = gpio.INVALID
}
}
}
const (
cSHigh spi.Mode = 0x4 // CS active high instead of default low (not recommended)
lSBFirst spi.Mode = 0x8 // Use little endian encoding for each word
threeWire spi.Mode = 0x10 // half-duplex; MOSI and MISO are shared
loop spi.Mode = 0x20 // loopback mode
noCS spi.Mode = 0x40 // do not assert CS
ready spi.Mode = 0x80 // slave pulls low to pause
// The driver optionally support dual and quad data lines.
)
// spidev driver IOCTL control codes.
//
// Constants and structure definition can be found at
// /usr/include/linux/spi/spidev.h.
const spiIOCMagic uint = 'k'
var (
spiIOCMode = fs.IOW(spiIOCMagic, 1, 1) // SPI_IOC_WR_MODE (8 bits)
spiIOLSBFirst = fs.IOW(spiIOCMagic, 2, 1) // SPI_IOC_WR_LSB_FIRST
spiIOCBitsPerWord = fs.IOW(spiIOCMagic, 3, 1) // SPI_IOC_WR_BITS_PER_WORD
spiIOCMaxSpeedHz = fs.IOW(spiIOCMagic, 4, 4) // SPI_IOC_WR_MAX_SPEED_HZ
spiIOCMode32 = fs.IOW(spiIOCMagic, 5, 4) // SPI_IOC_WR_MODE32 (32 bits)
)
// spiIOCTx(l) calculates the equivalent of SPI_IOC_MESSAGE(l) to execute a
// transaction.
func spiIOCTx(l int) uint {
return fs.IOW(spiIOCMagic, 0, uint(l)*32)
}
// spiIOCTransfer is spi_ioc_transfer in linux/spi/spidev.h.
//
// Also documented as struct spi_transfer at
// https://www.kernel.org/doc/html/latest/driver-api/spi.html
type spiIOCTransfer struct {
tx uint64 // Pointer to byte slice
rx uint64 // Pointer to byte slice
length uint32 // buffer length of tx and rx in bytes
speedHz uint32 // temporarily override the speed
delayUsecs uint16 // µs to sleep before selecting the device before the next transfer
bitsPerWord uint8 // temporarily override the number of bytes per word
csChange uint8 // true to deassert CS before next transfer
txNBits uint8
rxNBits uint8
pad uint16
}
func (s *spiIOCTransfer) reset(w, r []byte, f physic.Frequency, bitsPerWord uint8, csInvert bool) {
s.tx = 0
s.rx = 0
s.length = 0
// w and r must be the same length.
if l := len(w); l != 0 {
s.tx = uint64(uintptr(unsafe.Pointer(&w[0])))
s.length = uint32(l)
}
if l := len(r); l != 0 {
s.rx = uint64(uintptr(unsafe.Pointer(&r[0])))
s.length = uint32(l)
}
s.speedHz = uint32((f + 500*physic.MilliHertz) / physic.Hertz)
s.delayUsecs = 0
s.bitsPerWord = bitsPerWord
if csInvert {
s.csChange = 1
} else {
s.csChange = 0
}
s.txNBits = 0
s.rxNBits = 0
s.pad = 0
}
//
// driverSPI implements periph.Driver.
type driverSPI struct {
// bufSize is the maximum number of bytes allowed per I/O on the SPI port.
bufSize int
}
func (d *driverSPI) String() string {
return "sysfs-spi"
}
func (d *driverSPI) Prerequisites() []string {
return nil
}
func (d *driverSPI) After() []string {
return nil
}
func (d *driverSPI) Init() (bool, error) {
// This driver is only registered on linux, so there is no legitimate time to
// skip it.
// Do not use "/sys/bus/spi/devices/spi" as Raspbian's provided udev rules
// only modify the ACL of /dev/spidev* but not the ones in /sys/bus/...
prefix := "/dev/spidev"
items, err := filepath.Glob(prefix + "*")
if err != nil {
return true, err
}
if len(items) == 0 {
return false, errors.New("no SPI port found")
}
sort.Strings(items)
for _, item := range items {
parts := strings.Split(item[len(prefix):], ".")
if len(parts) != 2 {
continue
}
bus, err := strconv.Atoi(parts[0])
if err != nil {
continue
}
cs, err := strconv.Atoi(parts[1])
if err != nil {
continue
}
name := fmt.Sprintf("/dev/spidev%d.%d", bus, cs)
aliases := []string{fmt.Sprintf("SPI%d.%d", bus, cs)}
n := bus
if cs != 0 {
n = -1
}
if err := spireg.Register(name, aliases, n, (&openerSPI{bus, cs}).Open); err != nil {
return true, err
}
}
f, err := fs.Open("/sys/module/spidev/parameters/bufsiz", os.O_RDONLY)
if err != nil {
return true, err
}
defer f.Close()
b, err := ioutil.ReadAll(f)
if err != nil {
return true, err
}
// Update the global value.
drvSPI.bufSize, err = strconv.Atoi(strings.TrimSpace(string(b)))
return true, err
}
type openerSPI struct {
bus int
cs int
}
func (o *openerSPI) Open() (spi.PortCloser, error) {
return NewSPI(o.bus, o.cs)
}
func init() {
if isLinux {
periph.MustRegister(&drvSPI)
}
}
var drvSPI driverSPI
var _ conn.Limits = &SPI{}
var _ conn.Limits = &spiConn{}
var _ io.Reader = &spiConn{}
var _ io.Writer = &spiConn{}
var _ spi.Conn = &spiConn{}
var _ spi.Pins = &SPI{}
var _ spi.Pins = &spiConn{}
var _ spi.Port = &SPI{}
var _ spi.PortCloser = &SPI{}
var _ fmt.Stringer = &SPI{}

62
vendor/periph.io/x/periph/host/sysfs/sysfs.go generated vendored Normal file
View File

@ -0,0 +1,62 @@
// 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.
package sysfs
import (
"io"
"periph.io/x/periph/host/fs"
)
var ioctlOpen = ioctlOpenDefault
func ioctlOpenDefault(path string, flag int) (ioctlCloser, error) {
f, err := fs.Open(path, flag)
if err != nil {
return nil, err
}
return f, nil
}
var fileIOOpen = fileIOOpenDefault
func fileIOOpenDefault(path string, flag int) (fileIO, error) {
f, err := fs.Open(path, flag)
if err != nil {
return nil, err
}
return f, nil
}
type ioctlCloser interface {
io.Closer
fs.Ioctler
}
type fileIO interface {
Fd() uintptr
fs.Ioctler
io.Closer
io.Reader
io.Seeker
io.Writer
}
// seekRead seeks to the beginning of a file and reads it.
func seekRead(f fileIO, b []byte) (int, error) {
if _, err := f.Seek(0, 0); err != nil {
return 0, err
}
return f.Read(b)
}
// seekWrite seeks to the beginning of a file and writes to it.
func seekWrite(f fileIO, b []byte) error {
if _, err := f.Seek(0, 0); err != nil {
return err
}
_, err := f.Write(b)
return err
}

17
vendor/periph.io/x/periph/host/sysfs/sysfs_linux.go generated vendored Normal file
View File

@ -0,0 +1,17 @@
// 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 sysfs
import (
"os"
"syscall"
)
const isLinux = true
func isErrBusy(err error) bool {
e, ok := err.(*os.PathError)
return ok && e.Err == syscall.EBUSY
}

14
vendor/periph.io/x/periph/host/sysfs/sysfs_other.go generated vendored Normal file
View File

@ -0,0 +1,14 @@
// 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.
// +build !linux
package sysfs
const isLinux = false
func isErrBusy(err error) bool {
// This function is not used on non-linux.
return false
}

261
vendor/periph.io/x/periph/host/sysfs/thermal_sensor.go generated vendored Normal file
View File

@ -0,0 +1,261 @@
// 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 sysfs
import (
"errors"
"fmt"
"os"
"path/filepath"
"sort"
"strconv"
"sync"
"time"
"periph.io/x/periph"
"periph.io/x/periph/conn"
"periph.io/x/periph/conn/physic"
)
// ThermalSensors is all the sensors discovered on this host via sysfs. It
// includes 'thermal' devices as well as temperature 'hwmon' devices, so
// pre-configured onewire temperature sensors will be discovered automatically.
var ThermalSensors []*ThermalSensor
// ThermalSensorByName returns a *ThermalSensor for the sensor name, if any.
func ThermalSensorByName(name string) (*ThermalSensor, error) {
// TODO(maruel): Use a bisect or a map. For now we don't expect more than a
// handful of thermal sensors so it doesn't matter.
for _, t := range ThermalSensors {
if t.name == name {
if err := t.open(); err != nil {
return nil, err
}
return t, nil
}
}
return nil, errors.New("sysfs-thermal: invalid sensor name")
}
// ThermalSensor represents one thermal sensor on the system.
type ThermalSensor struct {
name string
root string
sensorFilename string
typeFilename string
mu sync.Mutex
nameType string
f fileIO
precision physic.Temperature
done chan struct{}
}
func (t *ThermalSensor) String() string {
return t.name
}
// Halt stops a continuous sense that was started with SenseContinuous.
func (t *ThermalSensor) Halt() error {
t.mu.Lock()
defer t.mu.Unlock()
if t.done != nil {
close(t.done)
t.done = nil
}
return nil
}
// Type returns the type of sensor as exported by sysfs.
func (t *ThermalSensor) Type() string {
t.mu.Lock()
defer t.mu.Unlock()
if t.nameType == "" {
nameType, err := t.readType()
if err != nil {
return err.Error()
}
t.nameType = nameType
}
return t.nameType
}
func (t *ThermalSensor) readType() (string, error) {
f, err := fileIOOpen(t.root+t.typeFilename, os.O_RDONLY)
if os.IsNotExist(err) {
return "<unknown>", nil
}
if err != nil {
return "", fmt.Errorf("sysfs-thermal: %v", err)
}
defer f.Close()
var buf [256]byte
n, err := f.Read(buf[:])
if err != nil {
return "", fmt.Errorf("sysfs-thermal: %v", err)
}
if n < 2 {
return "<unknown>", nil
}
return string(buf[:n-1]), nil
}
// Sense implements physic.SenseEnv.
func (t *ThermalSensor) Sense(e *physic.Env) error {
if err := t.open(); err != nil {
return err
}
t.mu.Lock()
defer t.mu.Unlock()
var buf [24]byte
n, err := seekRead(t.f, buf[:])
if err != nil {
return fmt.Errorf("sysfs-thermal: %v", err)
}
if n < 2 {
return errors.New("sysfs-thermal: failed to read temperature")
}
i, err := strconv.Atoi(string(buf[:n-1]))
if err != nil {
return fmt.Errorf("sysfs-thermal: %v", err)
}
if t.precision == 0 {
t.precision = physic.MilliKelvin
if i < 100 {
t.precision *= 1000
}
}
e.Temperature = physic.Temperature(i)*t.precision + physic.ZeroCelsius
return nil
}
// SenseContinuous implements physic.SenseEnv.
func (t *ThermalSensor) SenseContinuous(interval time.Duration) (<-chan physic.Env, error) {
t.mu.Lock()
defer t.mu.Unlock()
if t.done != nil {
return nil, nil
}
done := make(chan struct{})
ret := make(chan physic.Env)
ticker := time.NewTicker(interval)
go func() {
defer ticker.Stop()
for {
select {
case <-done:
close(ret)
return
case <-ticker.C:
var e physic.Env
if err := t.Sense(&e); err == nil {
ret <- e
}
}
}
}()
t.done = done
return ret, nil
}
// Precision implements physic.SenseEnv.
func (t *ThermalSensor) Precision(e *physic.Env) {
if t.precision == 0 {
dummy := physic.Env{}
// Ignore the error.
_ = t.Sense(&dummy)
}
t.mu.Lock()
defer t.mu.Unlock()
e.Temperature = t.precision
}
//
func (t *ThermalSensor) open() error {
t.mu.Lock()
defer t.mu.Unlock()
if t.f != nil {
return nil
}
f, err := fileIOOpen(t.root+t.sensorFilename, os.O_RDONLY)
if err != nil {
return fmt.Errorf("sysfs-thermal: %v", err)
}
t.f = f
return nil
}
// driverThermalSensor implements periph.Driver.
type driverThermalSensor struct {
}
func (d *driverThermalSensor) String() string {
return "sysfs-thermal"
}
func (d *driverThermalSensor) Prerequisites() []string {
return nil
}
func (d *driverThermalSensor) After() []string {
return nil
}
// Init initializes thermal sysfs handling code.
//
// Uses sysfs as described* at
// https://www.kernel.org/doc/Documentation/thermal/sysfs-api.txt
//
// * for the most minimalistic meaning of 'described'.
func (d *driverThermalSensor) Init() (bool, error) {
if err := d.discoverDevices("/sys/class/thermal/*/temp", "type"); err != nil {
return true, err
}
if err := d.discoverDevices("/sys/class/hwmon/*/temp*_input", "device/name"); err != nil {
return true, err
}
if len(ThermalSensors) == 0 {
return false, errors.New("sysfs-thermal: no sensor found")
}
return true, nil
}
func (d *driverThermalSensor) discoverDevices(glob, typeFilename string) error {
// This driver is only registered on linux, so there is no legitimate time to
// skip it.
items, err := filepath.Glob(glob)
if err != nil {
return err
}
if len(items) == 0 {
return nil
}
sort.Strings(items)
for _, item := range items {
base := filepath.Dir(item)
ThermalSensors = append(ThermalSensors, &ThermalSensor{
name: filepath.Base(base),
root: base + "/",
sensorFilename: filepath.Base(item),
typeFilename: typeFilename,
})
}
return nil
}
func init() {
if isLinux {
periph.MustRegister(&drvThermalSensor)
}
}
var drvThermalSensor driverThermalSensor
var _ conn.Resource = &ThermalSensor{}
var _ physic.SenseEnv = &ThermalSensor{}

229
vendor/periph.io/x/periph/host/videocore/videocore.go generated vendored Normal file
View File

@ -0,0 +1,229 @@
// 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 videocore interacts with the VideoCore GPU found on bcm283x.
//
// This package shouldn't be used directly, it is used by bcm283x's DMA
// implementation.
//
// Datasheet
//
// While not an actual datasheet, this is the closest to actual formal
// documentation:
// https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface
package videocore
import (
"fmt"
"os"
"sync"
"unsafe"
"periph.io/x/periph/host/fs"
"periph.io/x/periph/host/pmem"
)
// Mem represents contiguous physically locked memory that was allocated by
// VideoCore.
//
// The memory is mapped in user space.
type Mem struct {
*pmem.View
handle uint32
}
// Close unmaps the physical memory allocation.
//
// It is important to call this function otherwise the memory is locked until
// the host reboots.
func (m *Mem) Close() error {
if err := m.View.Close(); err != nil {
return wrapf("failed to close physical view: %v", err)
}
if _, err := mailboxTx32(mbUnlockMemory, m.handle); err != nil {
return wrapf("failed to unlock memory: %v", err)
}
if _, err := mailboxTx32(mbReleaseMemory, m.handle); err != nil {
return wrapf("failed to release memory: %v", err)
}
return nil
}
// Alloc allocates a continuous chunk of physical memory for use with DMA
// controller.
//
// Size must be rounded to 4Kb.
func Alloc(size int) (*Mem, error) {
if size <= 0 {
return nil, wrapf("memory size must be > 0; got %d", size)
}
if size&0xFFF != 0 {
return nil, wrapf("memory size must be rounded to 4096 pages; got %d", size)
}
if err := openMailbox(); err != nil {
return nil, wrapf("failed to open the mailbox to the GPU: %v", err)
}
// Size, Alignment, Flags; returns an opaque handle to be used to release the
// memory.
handle, err := mailboxTx32(mbAllocateMemory, uint32(size), 4096, flagDirect)
if err != nil {
return nil, wrapf("failed request to allocate memory: %v", err)
}
if handle == 0 {
return nil, wrapf("failed to allocate %d bytes", size)
}
// Lock the memory to retrieve a physical memory address.
p, err := mailboxTx32(mbLockMemory, handle)
if err != nil {
return nil, wrapf("failed request to lock memory: %v", err)
}
if p == 0 {
return nil, wrapf("failed to lock memory")
}
b, err := pmem.Map(uint64(p&^0xC0000000), size)
if err != nil {
return nil, wrapf("failed to memory map phyisical pages: %v", err)
}
return &Mem{View: b, handle: handle}, nil
}
//
var (
mu sync.Mutex
mailbox messager
mailboxErr error
mbIoctl = fs.IOWR('d', 0, uint(unsafe.Sizeof(new(byte))))
)
const (
// All of these return anything but zero (‽)
mbFirmwareVersion = 0x1 // 0, 4
mbBoardModel = 0x10001 // 0, 4
mbBoardRevision = 0x10002 // 0, 4
mbBoardMAC = 0x10003 // 0, 6
mbBoardSerial = 0x10004 // 0, 8
mbARMMemory = 0x10005 // 0, 8
mbVCMemory = 0x10006 // 0, 8
mbClocks = 0x10007 // 0, variable
// These work:
mbAllocateMemory = 0x3000C // 12, 4
mbLockMemory = 0x3000D // 4, 4
mbUnlockMemory = 0x3000E // 4, 4
mbReleaseMemory = 0x3000F // 4, 4
mbReply = 0x80000000 // High bit means a reply
flagDiscardable = 1 << 0 // Can be resized to 0 at any time. Use for cached data.
flagNormal = 0 << 2 // Normal allocating alias. Don't use from ARM.
flagDirect = 1 << 2 // 0xCxxxxxxx Uncached
flagCoherent = 2 << 2 // 0x8xxxxxxx Non-allocating in L2 but coherent
flagL1Nonallocating = flagDirect | flagCoherent // Allocating in L2
flagZero = 1 << 4 // Initialise buffer to all zeros
flagNoInit = 1 << 5 // Don't initialise (default is initialise to all ones
flagHintPermalock = 1 << 6 // Likely to be locked for long periods of time
)
type messager interface {
sendMessage(b []uint32) error
}
type messageBox struct {
f *fs.File
}
func (m *messageBox) sendMessage(b []uint32) error {
return m.f.Ioctl(mbIoctl, uintptr(unsafe.Pointer(&b[0])))
}
func openMailbox() error {
mu.Lock()
defer mu.Unlock()
if mailbox != nil || mailboxErr != nil {
return mailboxErr
}
f, err := fs.Open("/dev/vcio", os.O_RDWR|os.O_SYNC)
mailboxErr = err
if err == nil {
mailbox = &messageBox{f}
mailboxErr = smokeTest()
}
return mailboxErr
}
// genPacket creates a message to be sent to the GPU via the "mailbox".
//
// The message must be 16-byte aligned because only the upper 28 bits are
// passed; the lower bits are used to select the channel.
func genPacket(cmd uint32, replyLen uint32, args ...uint32) []uint32 {
p := make([]uint32, 48)
offset := uintptr(unsafe.Pointer(&p[0])) & 15
b := p[16-offset : 32+16-offset]
max := uint32(len(args) * 4)
if replyLen > max {
max = replyLen
}
max = ((max + 3) / 4) * 4
// size + zero + cmd + in + out + <max> + zero
b[0] = uint32(6*4) + max // message total length in bytes, including trailing zero
b[2] = cmd //
b[3] = uint32(len(args)) * 4 // inputs length in bytes
b[4] = replyLen // outputs length in bytes
copy(b[5:], args)
return b[:6+max/4]
}
func sendPacket(b []uint32) error {
if err := mailbox.sendMessage(b); err != nil {
return fmt.Errorf("failed to send IOCTL: %v", err)
}
if b[1] != mbReply {
// 0x80000001 means partial response.
return fmt.Errorf("got unexpected reply bit 0x%08x", b[1])
}
return nil
}
func mailboxTx32(cmd uint32, args ...uint32) (uint32, error) {
b := genPacket(cmd, 4, args...)
if err := sendPacket(b); err != nil {
return 0, err
}
if b[4] != mbReply|4 {
return 0, fmt.Errorf("got unexpected reply size 0x%08x", b[4])
}
return b[5], nil
}
/*
// mailboxTx is the generic version of mailboxTx32. It is not currently needed.
func mailboxTx(cmd uint32, reply []byte, args ...uint32) error {
b := genPacket(cmd, uint32(len(reply)), args...)
if err := sendPacket(b); err != nil {
return err
}
rep := b[4]
if rep&mbReply == 0 {
return fmt.Errorf("got unexpected reply size 0x%08x", b[4])
}
rep &^= mbReply
if rep == 0 || rep > uint32(len(reply)) {
return fmt.Errorf("got unexpected reply size 0x%08x", b[4])
}
return nil
}
*/
func smokeTest() error {
// It returns 0 on a RPi3 but don't assert this in case the VC firmware gets
// updated.
_, err := mailboxTx32(mbFirmwareVersion)
return err
}
func wrapf(format string, a ...interface{}) error {
return fmt.Errorf("videocore: "+format, a...)
}
var _ pmem.Mem = &Mem{}