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

359 lines
11 KiB
Go

// Copyright 2016 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
package chip
import (
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
"periph.io/x/conn/v3/driver/driverreg"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/gpio/gpioreg"
"periph.io/x/conn/v3/pin"
"periph.io/x/conn/v3/pin/pinreg"
"periph.io/x/host/v3/allwinner"
"periph.io/x/host/v3/distro"
"periph.io/x/host/v3/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 {
driverreg.MustRegister(&drv)
}
}
var drv driver