build: upgrade to go 1.17 and dependencies

This commit is contained in:
2021-09-01 21:34:31 +02:00
parent bb6726a4b2
commit 36482fc9b8
749 changed files with 110609 additions and 117714 deletions

433
vendor/periph.io/x/host/v3/.gohci.yml generated vendored Normal file
View File

@ -0,0 +1,433 @@
# Copyright 2021 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.
# See https://github.com/periph/gohci
version: 1
workers:
# BeagleBone Green Wireles by SeedStudio.
# https://beagleboard.org/green-wireless
- name: beaglebone-1860
checks:
- cmd:
- go
- test
- -cover
- -bench=.
- -benchtime=1000ms
- -benchmem
- ./...
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/devices
dir: ..
- cmd:
- go
- get
- periph.io/x/host/v3@${GIT_SHA}
dir: ../devices
- cmd:
- go
- test
- ./...
dir: ../devices
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/cmd
dir: ..
- cmd:
- go
- get
- periph.io/x/host/v3@${GIT_SHA}
dir: ../cmd
- cmd:
- go
- test
- ./...
dir: ../cmd
# Test commands.
- cmd:
- go
- install
- -v
- ./headers-list
- ./i2c-list
- ./periph-info
- ./periph-smoketest
- ./spi-list
dir: ../cmd
- cmd:
- periph-info
- cmd:
- headers-list
- -f
- cmd:
- i2c-list
- cmd:
- spi-list
- cmd:
- periph-smoketest
- gpio
- -pin1
- P8_45
- -pin2
- P8_46
# ODROID-C1+ by HardKernel
# https://www.hardkernel.com/shop/odroid-c1/
- name: odroid-483d
checks:
- cmd:
- go
- test
- -cover
- -bench=.
- -benchtime=1000ms
- -benchmem
- ./...
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/devices
dir: ..
- cmd:
- go
- get
- periph.io/x/host/v3@${GIT_SHA}
dir: ../devices
- cmd:
- go
- test
- ./...
dir: ../devices
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/cmd
dir: ..
- cmd:
- go
- get
- periph.io/x/host/v3@${GIT_SHA}
dir: ../cmd
- cmd:
- go
- test
- ./...
dir: ../cmd
# Test commands.
- cmd:
- go
- install
- -v
- ./gpio-list
- ./headers-list
- ./i2c-list
- ./periph-info
- ./periph-smoketest
- ./spi-list
dir: ../cmd
- cmd:
- periph-info
- cmd:
- gpio-list
- -f
- cmd:
- headers-list
- -f
- cmd:
- i2c-list
- cmd:
- spi-list
- cmd:
- periph-smoketest
- odroid-c1
- cmd:
- periph-smoketest
- i2c-testboard
- cmd:
- periph-smoketest
- onewire-testboard
- cmd:
- periph-smoketest
- spi-testboard
- cmd:
- periph-smoketest
- sysfs-benchmark
- -p
- 97
- -short
# Raspberry Pi 3
- name: raspberrypi-2f34
checks:
- cmd:
- go
- test
- -cover
- -bench=.
- -benchtime=1000ms
- -benchmem
- ./...
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/devices
dir: ..
- cmd:
- go
- get
- periph.io/x/host/v3@${GIT_SHA}
dir: ../devices
- cmd:
- go
- test
- ./...
dir: ../devices
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/cmd
dir: ..
- cmd:
- go
- get
- periph.io/x/host/v3@${GIT_SHA}
dir: ../cmd
- cmd:
- go
- test
- ./...
dir: ../cmd
# Test commands.
- cmd:
- go
- install
- -v
- ./gpio-list
- ./headers-list
- ./i2c-list
- ./periph-info
- ./periph-smoketest
- ./spi-list
dir: ../cmd
- cmd:
- periph-info
- cmd:
- gpio-list
- -f
- cmd:
- headers-list
- -f
- cmd:
- i2c-list
- cmd:
- spi-list
- cmd:
- periph-smoketest
- i2c-testboard
- cmd:
- periph-smoketest
- onewire-testboard
- -i2cbus
- 1
- cmd:
- periph-smoketest
- spi-testboard
- cmd:
- periph-smoketest
- sysfs-benchmark
- -p
- 12
- -short
- cmd:
- periph-smoketest
- bcm283x-benchmark
- -p
- 12
- -short
- cmd:
- periph-smoketest
- gpio
- -pin1
- P1_15
- -pin2
- P1_16
- cmd:
- periph-smoketest
- bcm283x
- -quick
# Old MacBook Pro on 10.9.
- name: mbp
checks:
- cmd:
- go
- test
- -cover
- -bench=.
- -benchtime=1000ms
- -benchmem
- ./...
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/devices
dir: ..
- cmd:
- go
- get
- periph.io/x/host/v3@${GIT_SHA}
dir: ../devices
- cmd:
- go
- test
- ./...
dir: ../devices
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/cmd
dir: ..
- cmd:
- go
- get
- periph.io/x/host/v3@${GIT_SHA}
dir: ../cmd
- cmd:
- go
- test
- ./...
dir: ../cmd
# Test commands.
- cmd:
- go
- install
- -v
- ./gpio-list
- ./headers-list
- ./i2c-list
- ./periph-info
- ./periph-smoketest
- ./spi-list
dir: ../cmd
- cmd:
- periph-info
- cmd:
- gpio-list
- -f
- cmd:
- headers-list
- -f
- cmd:
- i2c-list
- cmd:
- spi-list
# - cmd:
# - periph-smoketest
# - ftdi
# - -type
# - ft232r
# Laptop on Windows 10.
- name: win10
checks:
- cmd:
- go
- test
- -cover
- -bench=.
- -benchtime=1000ms
- -benchmem
- ./...
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/devices
dir: ..
- cmd:
- go
- get
- periph.io/x/host/v3@${GIT_SHA}
dir: ../devices
- cmd:
- go
- test
- ./...
dir: ../devices
# Test in advance.
- cmd:
- git
- clone
- --depth
- 1
- https://github.com/periph/cmd
dir: ..
- cmd:
- go
- get
- periph.io/x/host/v3@${GIT_SHA}
dir: ../cmd
- cmd:
- go
- test
- ./...
dir: ../cmd
# Test commands.
- cmd:
- go
- install
- -v
- ./gpio-list
- ./headers-list
- ./i2c-list
- ./periph-info
- ./periph-smoketest
- ./spi-list
dir: ../cmd
- cmd:
- periph-info
- cmd:
- gpio-list
- -f
- cmd:
- headers-list
- -f
- cmd:
- i2c-list
- cmd:
- spi-list
# - cmd:
# - periph-smoketest
# - ftdi
# - -type
# - ft232h

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

@ -0,0 +1,15 @@
# This is the list of The Periph Authors for copyright purposes.
#
# This does not necessarily list everyone who has contributed code, since in
# some cases, their employer may be the copyright holder. To see the full list
# of contributors, see the revision history in source control.
Cássio Botaro <cassiobotaro@gmail.com>
Fractal Industries, Inc
Google Inc.
Josh Gardiner
Matt Aimonetti <mattaimonetti@gmail.com>
Max Ekman <max@looplab.se>
Rifiniti, Inc
Stephan Sperber
Thorsten von Eicken <tve@voneicken.com>

4
vendor/periph.io/x/host/v3/CONTRIBUTING.md generated vendored Normal file
View File

@ -0,0 +1,4 @@
# Contributing
Thanks for contributing to the project! Please look at [the periph contribution
guidelines](https://periph.io/project/contributing/) first.

41
vendor/periph.io/x/host/v3/CONTRIBUTORS generated vendored Normal file
View File

@ -0,0 +1,41 @@
# This is the official list of people who can contribute
# (and typically have contributed) code to the periph repository.
# The AUTHORS file lists the copyright holders; this file
# lists people. For example, Google employees are listed here
# but not in AUTHORS, because Google holds the copyright.
#
# Names should be added to this file only after verifying that
# the individual or the individual's organization has agreed to
# the appropriate Contributor License Agreement, found here:
#
# https://cla.developers.google.com/
#
# When adding J Random Contributor's name to this file,
# either J's name or J's organization's name should be
# added to the AUTHORS file, depending on whether the
# individual or corporate CLA was used.
# Names should be added to this file like so:
# Individual's name <submission email address>
# Individual's name <submission email address> <email2> <emailN>
#
# An entry with multiple email addresses specifies that the
# first address should be used in the submit logs and
# that the other addresses should be recognized as the
# same person when interacting with Gerrit.
# Please keep the list sorted.
Cássio Botaro <cassiobotaro@gmail.com>
Eugene Dzhurynsky <jdevelop@gmail.com>
Hidetoshi Shimokawa <smkwhdts@gmail.com>
John Maguire <john.maguire@gmail.com>
Josh Gardiner <josh@zool.com>
Marc-Antoine Ruel <maruel@chromium.org> <maruel@gmail.com>
Matt Aimonetti <mattaimonetti@gmail.com>
Max Ekman <max@looplab.se>
Matias Insaurralde <matias@insaurral.de>
Seán C McCord <ulexus@gmail.com> <scm@cycoresys.com>
Stephan Sperber <sperberstephan@googlemail.com>
Thorsten von Eicken <tve@voneicken.com>

202
vendor/periph.io/x/host/v3/LICENSE generated vendored Normal file
View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

57
vendor/periph.io/x/host/v3/README.md generated vendored Normal file
View File

@ -0,0 +1,57 @@
# periph - Peripherals I/O in Go
Documentation is at https://periph.io
Join us for a chat on
[gophers.slack.com/messages/periph](https://gophers.slack.com/messages/periph),
get an [invite here](https://invite.slack.golangbridge.org/).
[![mascot](https://raw.githubusercontent.com/periph/website/master/site/static/img/periph-mascot-280.png)](https://periph.io/)
[![PkgGoDev](https://pkg.go.dev/badge/periph.io/x/host/v3)](https://pkg.go.dev/periph.io/x/host/v3)
[![Coverage
Status](https://codecov.io/gh/periph/host/graph/badge.svg)](https://codecov.io/gh/periph/host)
## Example
Blink a LED:
~~~go
package main
import (
"time"
"periph.io/x/conn/v3/gpio"
"periph.io/x/host/v3"
"periph.io/x/host/v3/rpi"
)
func main() {
host.Init()
t := time.NewTicker(500 * time.Millisecond)
for l := gpio.Low; ; l = !l {
rpi.P1_33.Out(l)
<-t.C
}
}
~~~
Curious? Look at [supported devices](https://periph.io/device/) for more
examples!
## Authors
`periph` was initiated with and passion by [Marc-Antoine
Ruel](https://github.com/maruel). The full list of contributors is in
[AUTHORS](https://github.com/periph/host/blob/main/AUTHORS) and
[CONTRIBUTORS](https://github.com/periph/host/blob/main/CONTRIBUTORS).
## Disclaimer
This is not an official Google product (experimental or otherwise), it
is just code that happens to be owned by Google.
This project is not affiliated with the Go project.

220
vendor/periph.io/x/host/v3/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/conn/v3/pin"
"periph.io/x/host/v3/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/host/v3/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/conn/v3/pin"
"periph.io/x/host/v3/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/host/v3/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/host/v3/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/host/v3/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/host/v3/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/conn/v3/driver/driverreg"
"periph.io/x/host/v3/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.
driverreg.MustRegister(&drvDMA)
}
}
var drvDMA driverDMA

33
vendor/periph.io/x/host/v3/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/host/v3/allwinner/gpio.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

563
vendor/periph.io/x/host/v3/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/conn/v3/driver/driverreg"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/gpio/gpioreg"
"periph.io/x/conn/v3/physic"
"periph.io/x/conn/v3/pin"
"periph.io/x/host/v3/pmem"
"periph.io/x/host/v3/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("no A64 CPU 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 {
driverreg.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/host/v3/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/host/v3/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/conn/v3/pin"
"periph.io/x/host/v3/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/host/v3/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/host/v3/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/host/v3/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/host/v3/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/conn/v3/driver/driverreg"
"periph.io/x/host/v3/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 {
driverreg.MustRegister(&drv)
}
}
var drv driver

7
vendor/periph.io/x/host/v3/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

9
vendor/periph.io/x/host/v3/am335x/am335x_other.go generated vendored Normal file
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/host/v3/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

7
vendor/periph.io/x/host/v3/bcm283x/bcm283x_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 bcm283x
const isArm = true

9
vendor/periph.io/x/host/v3/bcm283x/bcm283x_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 bcm283x
const isArm = true

9
vendor/periph.io/x/host/v3/bcm283x/bcm283x_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 bcm283x
const isArm = false

330
vendor/periph.io/x/host/v3/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/conn/v3/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)
}

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

File diff suppressed because it is too large Load Diff

42
vendor/periph.io/x/host/v3/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

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

File diff suppressed because it is too large Load Diff

234
vendor/periph.io/x/host/v3/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/conn/v3/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/host/v3/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/conn/v3/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/host/v3/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/conn/v3/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/host/v3/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/host/v3/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/host/v3/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/host/v3/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
}

7
vendor/periph.io/x/host/v3/beagle/black/black_arm.go generated vendored Normal file
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/host/v3/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/conn/v3/driver/driverreg"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/pin"
"periph.io/x/conn/v3/pin/pinreg"
"periph.io/x/host/v3/beagle/black"
"periph.io/x/host/v3/beagle/green"
"periph.io/x/host/v3/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", "sysfs-gpio"}
}
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 {
driverreg.MustRegister(&drv)
}
}
var drv driver

7
vendor/periph.io/x/host/v3/beagle/bone/bone_arm.go generated vendored Normal file
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

9
vendor/periph.io/x/host/v3/beagle/bone/bone_other.go generated vendored Normal file
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/host/v3/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/conn/v3/driver/driverreg"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/pin"
"periph.io/x/conn/v3/pin/pinreg"
"periph.io/x/host/v3/distro"
"periph.io/x/host/v3/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", "sysfs-gpio"}
}
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 {
driverreg.MustRegister(&drv)
}
}
var drv driver

7
vendor/periph.io/x/host/v3/beagle/green/green_arm.go generated vendored Normal file
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/host/v3/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/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

7
vendor/periph.io/x/host/v3/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/host/v3/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/host/v3/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

20
vendor/periph.io/x/host/v3/codecov.yml generated vendored Normal file
View File

@ -0,0 +1,20 @@
# Copyright 2020 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.
# https://docs.codecov.io/docs/codecovyml-reference
# and
# https://docs.codecov.io/docs/coverage-configuration
coverage:
precision: 1
range: "40...80"
round: nearest
status:
patch:
default:
target: 60%
threshold: 10%
project:
default:
target: 60%
threshold: 10%

83
vendor/periph.io/x/host/v3/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/host/v3/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/host/v3/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/host/v3/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/host/v3/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

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

@ -0,0 +1,84 @@
// 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
import (
"encoding/binary"
"io/ioutil"
)
// 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
}
// DTRevision returns the device revision (e.g. a02082 for the Raspberry Pi 3)
// from the Linux device tree, or 0 if the file is missing or malformed.
func DTRevision() uint32 {
mu.Lock()
defer mu.Unlock()
if dtRevisionRead {
return dtRevision
}
dtRevisionRead = true
if b, _ := ioutil.ReadFile("/proc/device-tree/system/linux,revision"); len(b) >= 4 {
dtRevision = binary.BigEndian.Uint32(b[:4])
}
return dtRevision
}
//
var (
dtModel string // cached /proc/device-tree/model
dtCompatible []string // cached /proc/device-tree/compatible
dtRevision uint32 // cached /proc/device-tree/system/linux,revision
dtRevisionRead bool
)
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/host/v3/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/host/v3/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

9
vendor/periph.io/x/host/v3/distro/distro_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 distro
const isArm = true

7
vendor/periph.io/x/host/v3/distro/distro_linux.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 isLinux = true

9
vendor/periph.io/x/host/v3/distro/distro_nonarm.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 distro
const isArm = false

9
vendor/periph.io/x/host/v3/distro/distro_nonlinux.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 !linux
package distro
const isLinux = false

10
vendor/periph.io/x/host/v3/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/host/v3/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/host/v3/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/host/v3/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/host/v3/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/host/v3/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/host/v3/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
)

878
vendor/periph.io/x/host/v3/ftdi/dev.go generated vendored Normal file
View File

@ -0,0 +1,878 @@
// 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 ftdi
import (
"context"
"errors"
"strconv"
"sync"
"periph.io/x/conn/v3"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/i2c"
"periph.io/x/conn/v3/physic"
"periph.io/x/conn/v3/spi"
)
// Info is the information gathered about the connected FTDI device.
//
// The data is gathered from the USB descriptor.
type Info struct {
// Opened is true if the device was successfully opened.
Opened bool
// Type is the FTDI device type.
//
// The value can be "FT232H", "FT232R", etc.
//
// An empty string means the type is unknown.
Type string
// VenID is the vendor ID from the USB descriptor information. It is expected
// to be 0x0403 (FTDI).
VenID uint16
// DevID is the product ID from the USB descriptor information. It is
// expected to be one of 0x6001, 0x6006, 0x6010, 0x6014.
DevID uint16
}
// Dev represents one FTDI device.
//
// There can be multiple FTDI devices connected to a host.
//
// The device may also export one or multiple of I²C, SPI buses. You need to
// either cast into the right hardware, but more simply use the i2creg / spireg
// bus/port registries.
type Dev interface {
// conn.Resource
String() string
Halt() error
// Info returns information about an opened device.
Info(i *Info)
// Header returns the GPIO pins exposed on the chip.
Header() []gpio.PinIO
// SetSpeed sets the base clock for all I/O transactions.
//
// The device defaults to its fastest speed.
SetSpeed(f physic.Frequency) error
// EEPROM returns the EEPROM content.
EEPROM(ee *EEPROM) error
// WriteEEPROM updates the EEPROM. Must be used carefully.
WriteEEPROM(ee *EEPROM) error
// EraseEEPROM erases the EEPROM. Must be used carefully.
EraseEEPROM() error
// UserArea reads and return the EEPROM part that can be used to stored user
// defined values.
UserArea() ([]byte, error)
// WriteUserArea updates the user area in the EEPROM.
//
// If the length of ua is less than the available space, is it zero extended.
WriteUserArea(ua []byte) error
}
// broken represents a device that couldn't be opened correctly.
//
// It returns an error message to help the user diagnose issues.
type broken struct {
index int
err error
name string
}
func (b *broken) String() string {
return b.name
}
func (b *broken) Halt() error {
return nil
}
func (b *broken) Info(i *Info) {
i.Opened = false
}
func (b *broken) Header() []gpio.PinIO {
return nil
}
func (b *broken) SetSpeed(f physic.Frequency) error {
return b.err
}
func (b *broken) EEPROM(ee *EEPROM) error {
return b.err
}
func (b *broken) WriteEEPROM(ee *EEPROM) error {
return b.err
}
func (b *broken) EraseEEPROM() error {
return b.err
}
func (b *broken) UserArea() ([]byte, error) {
return nil, b.err
}
func (b *broken) WriteUserArea(ua []byte) error {
return b.err
}
// generic represents a generic FTDI device.
//
// It is used for the models that this package doesn't fully support yet.
type generic struct {
// Immutable after initialization.
index int
h *handle
name string
}
func (f *generic) String() string {
return f.name
}
// Halt implements conn.Resource.
//
// This halts all operations going through this device.
func (f *generic) Halt() error {
return f.h.Reset()
}
// Info returns information about an opened device.
func (f *generic) Info(i *Info) {
i.Opened = true
i.Type = f.h.t.String()
i.VenID = f.h.venID
i.DevID = f.h.devID
}
// Header returns the GPIO pins exposed on the chip.
func (f *generic) Header() []gpio.PinIO {
return nil
}
func (f *generic) SetSpeed(freq physic.Frequency) error {
// TODO(maruel): Doc says the actual speed is 16x, confirm.
return f.h.SetBaudRate(freq)
}
func (f *generic) EEPROM(ee *EEPROM) error {
return f.h.ReadEEPROM(ee)
/*
if f.ee.Raw == nil {
if err := f.h.readEEPROM(&f.ee); err != nil {
return nil
}
if f.ee.Raw == nil {
// It's a fresh new device. Devices bought via Adafruit already have
// their EEPROM programmed with Adafruit branding but devices sold by
// CJMCU are not. Since d2xxGetDeviceInfo() above succeeded, we know the
// device type via the USB descriptor, which is sufficient to load the
// driver, which permits to program the EEPROM to "bootstrap" it.
f.ee.Raw = []byte{}
}
}
*ee = f.ee
return nil
*/
}
func (f *generic) WriteEEPROM(ee *EEPROM) error {
// TODO(maruel): Compare with the cached EEPROM, and only update the
// different values if needed so reduce the EEPROM wear.
// f.h.h.d2xxWriteEE()
return f.h.WriteEEPROM(ee)
}
func (f *generic) EraseEEPROM() error {
return f.h.EraseEEPROM()
}
func (f *generic) UserArea() ([]byte, error) {
return f.h.ReadUA()
}
func (f *generic) WriteUserArea(ua []byte) error {
return f.h.WriteUA(ua)
}
//
func newFT232H(g generic) (*FT232H, error) {
f := &FT232H{
generic: g,
cbus: gpiosMPSSE{h: g.h, cbus: true},
dbus: gpiosMPSSE{h: g.h},
c8: invalidPin{num: 16, n: g.name + ".C8"}, // , dp: gpio.PullUp
c9: invalidPin{num: 17, n: g.name + ".C9"}, // , dp: gpio.PullUp
}
f.cbus.init(f.name)
f.dbus.init(f.name)
for i := range f.dbus.pins {
f.hdr[i] = &f.dbus.pins[i]
}
for i := range f.cbus.pins {
f.hdr[i+8] = &f.cbus.pins[i]
}
// TODO(maruel): C8 and C9 can be used when their mux in the EEPROM is set to
// ft232hCBusIOMode.
f.hdr[16] = &f.c8
f.hdr[17] = &f.c9
f.D0 = f.hdr[0]
f.D1 = f.hdr[1]
f.D2 = f.hdr[2]
f.D3 = f.hdr[3]
f.D4 = f.hdr[4]
f.D5 = f.hdr[5]
f.D6 = f.hdr[6]
f.D7 = f.hdr[7]
f.C0 = f.hdr[8]
f.C1 = f.hdr[9]
f.C2 = f.hdr[10]
f.C3 = f.hdr[11]
f.C4 = f.hdr[12]
f.C5 = f.hdr[13]
f.C6 = f.hdr[14]
f.C7 = f.hdr[15]
f.C8 = f.hdr[16]
f.C9 = f.hdr[17]
// This function forces all pins as inputs.
if err := f.h.InitMPSSE(); err != nil {
return nil, err
}
f.s.c.f = f
f.i.f = f
return f, nil
}
// FT232H represents a FT232H device.
//
// It implements Dev.
//
// The FT232H has 1024 bytes output buffer and 1024 bytes input buffer. It
// supports 512 bytes USB packets.
//
// The device can be used in a few different modes, two modes are supported:
//
// - D0~D3 as a serial protocol (MPSEE), supporting I²C and SPI (and eventually
// UART), In this mode, D4~D7 and C0~C7 can be used as synchronized GPIO.
//
// - D0~D7 as a synchronous 8 bits bit-bang port. In this mode, only a few pins
// on CBus are usable in slow mode.
//
// Each group of pins D0~D7 and C0~C7 can be changed at once in one pass via
// DBus() or CBus().
//
// This enables usage as an 8 bit parallel port.
//
// Pins C8 and C9 can only be used in 'slow' mode via EEPROM and are currently
// not implemented.
//
// Datasheet
//
// http://www.ftdichip.com/Support/Documents/DataSheets/ICs/DS_FT232H.pdf
type FT232H struct {
generic
D0 gpio.PinIO // Clock output
D1 gpio.PinIO // Data out
D2 gpio.PinIO // Data in
D3 gpio.PinIO // Chip select
D4 gpio.PinIO
D5 gpio.PinIO
D6 gpio.PinIO
D7 gpio.PinIO
C0 gpio.PinIO
C1 gpio.PinIO
C2 gpio.PinIO
C3 gpio.PinIO
C4 gpio.PinIO
C5 gpio.PinIO
C6 gpio.PinIO
C7 gpio.PinIO
C8 gpio.PinIO // Not implemented
C9 gpio.PinIO // Not implemented
hdr [18]gpio.PinIO
cbus gpiosMPSSE
dbus gpiosMPSSE
c8 invalidPin // gpio.PullUp
c9 invalidPin // gpio.PullUp
mu sync.Mutex
usingI2C bool
usingSPI bool
i i2cBus
s spiMPSEEPort
// TODO(maruel): Technically speaking, a SPI port could be hacked up too in
// sync bit-bang but there's less point when MPSEE is available.
}
// Header returns the GPIO pins exposed on the chip.
func (f *FT232H) Header() []gpio.PinIO {
out := make([]gpio.PinIO, len(f.hdr))
copy(out, f.hdr[:])
return out
}
func (f *FT232H) SetSpeed(freq physic.Frequency) error {
// TODO(maruel): When using MPSEE, use the MPSEE command. If using sync
// bit-bang, use SetBaudRate().
// TODO(maruel): Doc says the actual speed is 16x, confirm.
return f.h.SetBaudRate(freq)
}
// CBus sets the values of C0 to C7 in the specified direction and value.
//
// 0 direction means input, 1 means output.
func (f *FT232H) CBus(direction, value byte) error {
return f.h.MPSSECBus(direction, value)
}
// DBus sets the values of D0 to d7 in the specified direction and value.
//
// 0 direction means input, 1 means output.
//
// This function must be used to set Clock idle level.
func (f *FT232H) DBus(direction, value byte) error {
return f.h.MPSSEDBus(direction, value)
}
// CBusRead reads the values of C0 to C7.
func (f *FT232H) CBusRead() (byte, error) {
return f.h.MPSSECBusRead()
}
// DBusRead reads the values of D0 to D7.
func (f *FT232H) DBusRead() (byte, error) {
return f.h.MPSSEDBusRead()
}
// I2C returns an I²C bus over the AD bus.
//
// pull can be either gpio.PullUp or gpio.Float. The recommended pull up
// resistors are 10kΩ for 100kHz and 2kΩ for 400kHz when using Float. The
// GPIO's pull up is 75kΩ, which may require using a lower speed for signal
// reliability. Optimal pull up resistor calculation depends on the capacitance.
//
// It uses D0, D1 and D2.
//
// D0 is SCL. It must to be pulled up externally.
//
// D1 and D2 are used for SDA. D1 is the output using open drain, D2 is the
// input. D1 and D2 must be wired together and must be pulled up externally.
//
// It is recommended to set the mode to 245 FIFO in the EEPROM of the FT232H.
//
// The FIFO mode is recommended because it allows the ADbus lines to start as
// tristate. If the chip starts in the default UART mode, then the ADbus lines
// will be in the default UART idle states until the application opens the port
// and configures it as MPSSE. Care should also be taken that the RD# input on
// ACBUS is not asserted in this initial state as this can cause the FIFO lines
// to drive out.
func (f *FT232H) I2C(pull gpio.Pull) (i2c.BusCloser, error) {
if pull != gpio.PullUp && pull != gpio.Float {
return nil, errors.New("d2xx: I²C pull can only be PullUp or Float")
}
f.mu.Lock()
defer f.mu.Unlock()
if f.usingI2C {
return nil, errors.New("d2xx: already using I²C")
}
if f.usingSPI {
return nil, errors.New("d2xx: already using SPI")
}
if err := f.i.setupI2C(pull == gpio.PullUp); err != nil {
_ = f.i.stopI2C()
return nil, err
}
return &f.i, nil
}
// SPI returns a SPI port over the AD bus.
//
// It uses D0, D1, D2 and D3. D0 is the clock, D1 the output (MOSI), D2 is the
// input (MISO) and D3 is CS line.
func (f *FT232H) SPI() (spi.PortCloser, error) {
f.mu.Lock()
defer f.mu.Unlock()
if f.usingI2C {
return nil, errors.New("d2xx: already using I²C")
}
if f.usingSPI {
return nil, errors.New("d2xx: already using SPI")
}
// Don't mark it as being used yet. It only become used once Connect() is
// called.
return &f.s, nil
}
//
func newFT232R(g generic) (*FT232R, error) {
f := &FT232R{
generic: g,
dbus: [...]dbusPinSync{{num: 0}, {num: 1}, {num: 2}, {num: 3}, {num: 4}, {num: 5}, {num: 6}, {num: 7}},
cbus: [...]cbusPin{{num: 8, p: gpio.PullUp}, {num: 9, p: gpio.PullUp}, {num: 10, p: gpio.PullUp}, {num: 11, p: gpio.Float}},
}
// Use the UART names, as this is how all FT232R boards are marked.
dnames := [...]string{"TX", "RX", "RTS", "CTS", "DTR", "DSR", "DCD", "RI"}
for i := range f.dbus {
f.dbus[i].n = f.name + "." + dnames[i]
f.dbus[i].bus = f
f.hdr[i] = &f.dbus[i]
}
for i := range f.cbus {
f.cbus[i].n = f.name + ".C" + strconv.Itoa(i)
f.cbus[i].bus = f
f.hdr[i+8] = &f.cbus[i]
}
f.D0 = f.hdr[0]
f.D1 = f.hdr[1]
f.D2 = f.hdr[2]
f.D3 = f.hdr[3]
f.D4 = f.hdr[4]
f.D5 = f.hdr[5]
f.D6 = f.hdr[6]
f.D7 = f.hdr[7]
f.TX = f.hdr[0]
f.RX = f.hdr[1]
f.RTS = f.hdr[2]
f.CTS = f.hdr[3]
f.DTR = f.hdr[4]
f.DSR = f.hdr[5]
f.DCD = f.hdr[6]
f.RI = f.hdr[7]
f.C0 = f.hdr[8]
f.C1 = f.hdr[9]
f.C2 = f.hdr[10]
f.C3 = f.hdr[11]
// Default to 3MHz.
if err := f.h.SetBaudRate(3 * physic.MegaHertz); err != nil {
return nil, err
}
// Set all CBus pins as input.
if err := f.h.SetBitMode(0, bitModeCbusBitbang); err != nil {
return nil, err
}
// And read their value.
// TODO(maruel): Sadly this is impossible to know which pin is input or
// output, but we could try to guess, as the call above may generate noise on
// the line which could interfere with the device connected.
var err error
if f.cbusnibble, err = f.h.GetBitMode(); err != nil {
return nil, err
}
// Set all DBus as asynchronous bitbang, everything as input.
if err := f.h.SetBitMode(0, bitModeAsyncBitbang); err != nil {
return nil, err
}
// And read their value.
var b [1]byte
if _, err := f.h.ReadAll(context.Background(), b[:]); err != nil {
return nil, err
}
f.dvalue = b[0]
f.s.c.f = f
return f, nil
}
// FT232R represents a FT232RL/FT232RQ device.
//
// It implements Dev.
//
// Not all pins may be physically connected on the header!
//
// Adafruit's version only has the following pins connected: RX, TX, RTS and
// CTS.
//
// SparkFun's version exports all pins *except* (inexplicably) the CBus ones.
//
// The FT232R has 128 bytes output buffer and 256 bytes input buffer.
//
// Pin C4 can only be used in 'slow' mode via EEPROM and is currently not
// implemented.
//
// Datasheet
//
// http://www.ftdichip.com/Support/Documents/DataSheets/ICs/DS_FT232R.pdf
type FT232R struct {
generic
// Pin and their alias to the Dn pins for user convenience. Each pair points
// to the exact same pin.
D0, TX gpio.PinIO // Transmit; SPI_MOSI
D1, RX gpio.PinIO // Receive; SPI_MISO
D2, RTS gpio.PinIO // Request To Send Control Output / Handshake signal; SPI_CLK
D3, CTS gpio.PinIO // Clear to Send Control input / Handshake signal; SPI_CS
D4, DTR gpio.PinIO // Data Terminal Ready Control Output / Handshake signal
D5, DSR gpio.PinIO // Data Set Ready Control Input / Handshake signal
D6, DCD gpio.PinIO // Data Carrier Detect Control input
D7, RI gpio.PinIO // Ring Indicator Control Input. When remote wake up is enabled in the internal EEPROM taking RI# low can be used to resume the PC USB host controller from suspend.
// The CBus pins are slower to use, but can drive an high load, like a LED.
C0 gpio.PinIO
C1 gpio.PinIO
C2 gpio.PinIO
C3 gpio.PinIO
dbus [8]dbusPinSync
cbus [4]cbusPin
hdr [12]gpio.PinIO
// Mutable.
mu sync.Mutex
usingSPI bool
usingCBus bool
s spiSyncPort
dmask uint8 // 0 input, 1 output
dvalue uint8
cbusnibble uint8 // upper nibble is I/O control, lower nibble is values.
}
// Header returns the GPIO pins exposed on the chip.
func (f *FT232R) Header() []gpio.PinIO {
out := make([]gpio.PinIO, len(f.hdr))
copy(out, f.hdr[:])
return out
}
// SetDBusMask sets all D0~D7 input or output mode at once.
//
// mask is the input/output pins to use. A bit value of 0 sets the
// corresponding pin to an input, a bit value of 1 sets the corresponding pin
// to an output.
//
// It should be called before calling Tx().
func (f *FT232R) SetDBusMask(mask uint8) error {
f.mu.Lock()
defer f.mu.Unlock()
if f.usingSPI {
return errors.New("d2xx: already using SPI")
}
return f.setDBusMaskLocked(mask)
}
// Tx does synchronized read-then-write on all the D0~D7 GPIOs.
//
// SetSpeed() determines the pace at which the I/O is done.
//
// SetDBusMask() determines which bits are interpreted in the w and r byte
// slice. w has its significant value masked by 'mask' and r has its
// significant value masked by '^mask'.
//
// Input sample is done *before* updating outputs. So r[0] is sampled before
// w[0] is used. The last w byte should be duplicated if an addition read is
// desired.
//
// On the Adafruit cable, only the first 4 bits D0(TX), D1(RX), D2(RTS) and
// D3(CTS) are connected. This is just enough to create a full duplex SPI bus!
func (f *FT232R) Tx(w, r []byte) error {
if len(w) != 0 {
if len(r) != 0 && len(w) != len(r) {
return errors.New("d2xx: length of buffer w and r must match")
}
} else if len(r) == 0 {
return errors.New("d2xx: at least one of w or r must be passed")
}
f.mu.Lock()
defer f.mu.Unlock()
if f.usingSPI {
return errors.New("d2xx: already using SPI")
}
return f.txLocked(w, r)
}
// SPI returns a SPI port over the first 4 pins.
//
// It uses D0(TX), D1(RX), D2(RTS) and D3(CTS). D2(RTS) is the clock, D0(TX)
// the output (MOSI), D1(RX) is the input (MISO) and D3(CTS) is CS line.
func (f *FT232R) SPI() (spi.PortCloser, error) {
f.mu.Lock()
defer f.mu.Unlock()
if f.usingSPI {
return nil, errors.New("d2xx: already using SPI")
}
// Don't mark it as being used yet. It only become used once Connect() is
// called.
return &f.s, nil
}
// setDBusMaskLocked is the locked version of SetDBusMask.
func (f *FT232R) setDBusMaskLocked(mask uint8) error {
if mask != f.dmask {
if err := f.h.SetBitMode(mask, bitModeAsyncBitbang); err != nil {
return err
}
f.dmask = mask
}
return nil
}
func (f *FT232R) txLocked(w, r []byte) error {
// Investigate FT232R clock issue:
// http://developer.intra2net.com/mailarchive/html/libftdi/2010/msg00240.html
// The FT232R has 128 bytes TX buffer and 256 bytes RX buffer. Chunk into 64
// bytes chunks. That's half the buffer size of the TX buffer and permits
// pipelining and removes the risk of buffer overrun. This is important
// otherwise there's huge gaps due to the USB transmit overhead.
// TODO(maruel): Determine what's optimal via experimentation.
chunk := 64
var scratch [128]byte
if len(w) == 0 {
// Read only.
for i := range scratch {
scratch[i] = f.dvalue
}
for len(r) != 0 {
// TODO(maruel): Optimize.
c := len(r)
if c > chunk {
c = chunk
}
if _, err := f.h.Write(scratch[:c]); err != nil {
return err
}
if _, err := f.h.ReadAll(context.Background(), r[:c]); err != nil {
return err
}
r = r[c:]
}
} else if len(r) == 0 {
// Write only.
// The first write is 128 bytes to fill the buffer.
chunk = 128
for len(w) != 0 {
c := len(w)
if c > chunk {
c = chunk
}
if _, err := f.h.Write(w[:c]); err != nil {
return err
}
w = w[c:]
chunk = 64
}
/*
// Let the USB drive pace it.
if _, err := f.h.Write(w); err != nil {
return err
}
*/
} else {
// R/W.
// Always write one 'w' ahead.
// The first write is 128 bytes to fill the buffer.
chunk = 128
cw := len(w)
if cw > chunk {
cw = chunk
}
if _, err := f.h.Write(w[:cw]); err != nil {
return err
}
w = w[cw:]
chunk = 64
for len(r) != 0 {
// Read then write.
cr := len(r)
if cr > chunk {
cr = chunk
}
if _, err := f.h.ReadAll(context.Background(), r[:cr]); err != nil {
return err
}
r = r[cr:]
cw = len(w)
if cw > chunk {
cw = chunk
}
if cw != 0 {
if _, err := f.h.Write(w[:cw]); err != nil {
return err
}
w = w[cw:]
}
}
}
return nil
}
// dbusSyncGPIOFunc implements dbusSync. It returns the function of a GPIO
// pin.
func (f *FT232R) dbusSyncGPIOFunc(n int) string {
f.mu.Lock()
defer f.mu.Unlock()
if f.usingSPI {
switch n {
case 0:
return "SPI_MOSI" // TX
case 1:
return "SPI_MISO" // RX
case 2:
return "SPI_CLK" // RTS
case 3:
return "SPI_CS" // CTS
}
}
mask := uint8(1 << uint(n))
if f.dmask&mask != 0 {
return "Out/" + gpio.Level(f.dvalue&mask != 0).String()
}
return "In/" + f.dbusSyncReadLocked(n).String()
}
// dbusSyncGPIOIn implements dbusSync.
func (f *FT232R) dbusSyncGPIOIn(n int) error {
f.mu.Lock()
defer f.mu.Unlock()
// TODO(maruel): if f.usingSPI && n < 4.
mask := uint8(1 << uint(n))
if f.dmask&mask == 0 {
// Already input.
return nil
}
v := f.dmask &^ mask
if err := f.h.SetBitMode(v, bitModeAsyncBitbang); err != nil {
return err
}
f.dmask = v
return nil
}
// dbusSyncGPIORead implements dbusSync.
func (f *FT232R) dbusSyncGPIORead(n int) gpio.Level {
f.mu.Lock()
defer f.mu.Unlock()
return f.dbusSyncReadLocked(n)
}
func (f *FT232R) dbusSyncReadLocked(n int) gpio.Level {
// In synchronous mode, to read we must write first to for a sample.
b := [1]byte{f.dvalue}
if _, err := f.h.Write(b[:]); err != nil {
return gpio.Low
}
mask := uint8(1 << uint(n))
if _, err := f.h.ReadAll(context.Background(), b[:]); err != nil {
return gpio.Low
}
f.dvalue = b[0]
return f.dvalue&mask != 0
}
// dbusSyncGPIOOut implements dbusSync.
func (f *FT232R) dbusSyncGPIOOut(n int, l gpio.Level) error {
f.mu.Lock()
defer f.mu.Unlock()
mask := uint8(1 << uint(n))
if f.dmask&mask != 1 {
// Was input.
v := f.dmask | mask
if err := f.h.SetBitMode(v, bitModeAsyncBitbang); err != nil {
return err
}
f.dmask = v
}
return f.dbusSyncGPIOOutLocked(n, l)
}
func (f *FT232R) dbusSyncGPIOOutLocked(n int, l gpio.Level) error {
b := [1]byte{f.dvalue}
if _, err := f.h.Write(b[:]); err != nil {
return err
}
f.dvalue = b[0]
// In synchronous mode, we must read after writing to flush the buffer.
if _, err := f.h.Write(b[:]); err != nil {
return err
}
return nil
}
// cBusGPIOFunc implements cBusGPIO.
func (f *FT232R) cBusGPIOFunc(n int) string {
f.mu.Lock()
defer f.mu.Unlock()
fmask := uint8(0x10 << uint(n))
vmask := uint8(1 << uint(n))
if f.cbusnibble&fmask != 0 {
return "Out/" + gpio.Level(f.cbusnibble&vmask != 0).String()
}
return "In/" + f.cBusReadLocked(n).String()
}
// cBusGPIOIn implements cBusGPIO.
func (f *FT232R) cBusGPIOIn(n int) error {
f.mu.Lock()
defer f.mu.Unlock()
fmask := uint8(0x10 << uint(n))
if f.cbusnibble&fmask == 0 {
// Already input.
return nil
}
v := f.cbusnibble &^ fmask
if err := f.h.SetBitMode(v, bitModeCbusBitbang); err != nil {
return err
}
f.cbusnibble = v
return nil
}
// cBusGPIORead implements cBusGPIO.
func (f *FT232R) cBusGPIORead(n int) gpio.Level {
f.mu.Lock()
defer f.mu.Unlock()
return f.cBusReadLocked(n)
}
func (f *FT232R) cBusReadLocked(n int) gpio.Level {
v, err := f.h.GetBitMode()
if err != nil {
return gpio.Low
}
f.cbusnibble = v
vmask := uint8(1 << uint(n))
return f.cbusnibble&vmask != 0
}
// cBusGPIOOut implements cBusGPIO.
func (f *FT232R) cBusGPIOOut(n int, l gpio.Level) error {
f.mu.Lock()
defer f.mu.Unlock()
fmask := uint8(0x10 << uint(n))
vmask := uint8(1 << uint(n))
v := f.cbusnibble | fmask
if l {
v |= vmask
} else {
v &^= vmask
}
if f.cbusnibble == v {
// Was already in the right mode.
return nil
}
if err := f.h.SetBitMode(v, bitModeCbusBitbang); err != nil {
return err
}
f.cbusnibble = v
return nil
}
//
var _ conn.Resource = Dev(nil)

20
vendor/periph.io/x/host/v3/ftdi/doc.go generated vendored Normal file
View File

@ -0,0 +1,20 @@
// 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 ftdi implements support for popular FTDI devices.
//
// The supported devices (FT232h/FT232r) implement support for various
// protocols like the GPIO, I²C, SPI, UART, JTAG.
//
// More details
//
// See https://periph.io/device/ftdi/ for more details, and how to configure
// the host to be able to use this driver.
//
// Datasheets
//
// http://www.ftdichip.com/Support/Documents/DataSheets/ICs/DS_FT232R.pdf
//
// http://www.ftdichip.com/Support/Documents/DataSheets/ICs/DS_FT232H.pdf
package ftdi

213
vendor/periph.io/x/host/v3/ftdi/driver.go generated vendored Normal file
View File

@ -0,0 +1,213 @@
// 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 ftdi
import (
"strconv"
"sync"
"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/i2c"
"periph.io/x/conn/v3/i2c/i2creg"
"periph.io/x/conn/v3/pin"
"periph.io/x/conn/v3/pin/pinreg"
"periph.io/x/conn/v3/spi/spireg"
"periph.io/x/d2xx"
)
// All enumerates all the connected FTDI devices.
func All() []Dev {
drv.mu.Lock()
defer drv.mu.Unlock()
out := make([]Dev, len(drv.all))
copy(out, drv.all)
return out
}
//
// open opens a FTDI device.
//
// Must be called with mu held.
func open(opener func(i int) (d2xx.Handle, d2xx.Err), i int) (Dev, error) {
h, err := openHandle(opener, i)
if err != nil {
return nil, err
}
if err := h.Init(); err != nil {
// setupCommon() takes the device in its previous state. It could be in an
// unexpected state, so try resetting it first.
if err := h.Reset(); err != nil {
_ = h.Close()
return nil, err
}
if err := h.Init(); err != nil {
_ = h.Close()
return nil, err
}
// The second attempt worked.
}
// Makes a copy of the handle.
g := generic{index: i, h: h, name: h.t.String()}
if i > 0 {
// When more than one device is present, add "(index)" suffix.
// TODO(maruel): Using the serial number would be nicer than a number.
g.name += "(" + strconv.Itoa(i) + ")"
}
// Makes a copy of the generic instance.
switch g.h.t {
case DevTypeFT232H:
f, err := newFT232H(g)
if err != nil {
_ = h.Close()
return nil, err
}
return f, nil
case DevTypeFT2232H:
f, err := newFT232H(g)
if err != nil {
_ = h.Close()
return nil, err
}
return f, nil
case DevTypeFT232R:
f, err := newFT232R(g)
if err != nil {
_ = h.Close()
return nil, err
}
return f, nil
default:
return &g, nil
}
}
// registerDev registers the header and supported buses and ports in the
// relevant registries.
func registerDev(d Dev, multi bool) error {
name := d.String()
hdr := d.Header()
// Register the GPIOs.
for _, p := range hdr {
if err := gpioreg.Register(p); err != nil {
return err
}
}
if !multi {
// Register shorthands.
// The "." used here vs the "_" used in pinreg is unfortunate. Investigate
// a better way.
prefix := len(name) + 1
for _, p := range hdr {
n := p.Name()
if err := gpioreg.RegisterAlias(n[prefix:], n); err != nil {
return err
}
}
}
// Register the header.
raw := make([][]pin.Pin, len(hdr))
for i := range hdr {
raw[i] = []pin.Pin{hdr[i]}
}
if err := pinreg.Register(name, raw); err != nil {
return err
}
switch t := d.(type) {
case *FT232H:
// Register I²C without pull up.
if err := i2creg.Register(name, nil, -1, func() (i2c.BusCloser, error) { return t.I2C(gpio.Float) }); err != nil {
return err
}
if err := spireg.Register(name, nil, -1, t.SPI); err != nil {
return err
}
// TODO(maruel): UART
case *FT232R:
// TODO(maruel): SPI, UART
}
return nil
}
// driver implements driver.Impl.
type driver struct {
mu sync.Mutex
all []Dev
d2xxOpen func(i int) (d2xx.Handle, d2xx.Err)
numDevices func() (int, error)
}
func (d *driver) String() string {
return "ftdi"
}
func (d *driver) Prerequisites() []string {
return nil
}
func (d *driver) After() []string {
return nil
}
func (d *driver) Init() (bool, error) {
num, err := d.numDevices()
if err != nil {
return true, err
}
multi := num > 1
for i := 0; i < num; i++ {
// TODO(maruel): Close the device one day. :)
if dev, err1 := open(d.d2xxOpen, i); err1 == nil {
d.all = append(d.all, dev)
if err = registerDev(dev, multi); err != nil {
return true, err
}
} else {
// Create a shallow broken handle, so the user can learn how to fix the
// problem.
//
// TODO(maruel): On macOS with a FT232R, calling two processes in a row
// often results in a broken device on the second process. Figure out why
// and make it more resilient.
err = err1
// The serial number is not available so what can be listed is limited.
// TODO(maruel): Add VID/PID?
name := "broken#" + strconv.Itoa(i) + ": " + err.Error()
d.all = append(d.all, &broken{index: i, err: err, name: name})
}
}
return true, err
}
func (d *driver) reset() {
d.mu.Lock()
defer d.mu.Unlock()
d.all = nil
// open is mocked in tests.
d.d2xxOpen = d2xx.Open
// numDevices is mocked in tests.
d.numDevices = numDevices
// The d2xx can hang for up to the timeout under certain circumstances and the
// Go profiler is not very useful to find the source, so use manual logging
// to see where time it spent.
//d.d2xxOpen = func(i int) (d2xx.Handle, int) {
// h, e := d2xxOpen(i)
// return &d2xxLoggingHandle{h}, e
//}
}
func init() {
if d2xx.Available {
drv.reset()
driverreg.MustRegister(&drv)
}
}
var drv driver

368
vendor/periph.io/x/host/v3/ftdi/eeprom.go generated vendored Normal file
View File

@ -0,0 +1,368 @@
// 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 ftdi
import (
"errors"
"fmt"
"unsafe"
)
// EEPROM is the unprocessed EEPROM content.
//
// The EEPROM is in 3 parts: the defined struct, the 4 strings and the rest
// which is used as an 'user area'. The size of the user area depends on the
// length of the strings. The user area content is not included in this struct.
type EEPROM struct {
// Raw is the raw EEPROM content. It excludes the strings.
Raw []byte
// The following condition must be true: len(Manufacturer) + len(Desc) <= 40.
Manufacturer string
ManufacturerID string
Desc string
Serial string
}
// Validate checks that the data is good.
func (e *EEPROM) Validate() error {
// Verify that the values are set correctly.
if len(e.Manufacturer) > 40 {
return errors.New("ftdi: Manufacturer is too long")
}
if len(e.ManufacturerID) > 40 {
return errors.New("ftdi: ManufacturerID is too long")
}
if len(e.Desc) > 40 {
return errors.New("ftdi: Desc is too long")
}
if len(e.Serial) > 40 {
return errors.New("ftdi: Serial is too long")
}
if len(e.Manufacturer)+len(e.Desc) > 40 {
return errors.New("ftdi: length of Manufacturer plus Desc is too long")
}
return nil
}
func (e *EEPROM) AsHeader() *EEPROMHeader {
// sizeof(EEPROMHeader)
if len(e.Raw) < 16 {
return nil
}
return (*EEPROMHeader)(unsafe.Pointer(&e.Raw[0]))
}
// AsFT232H returns the Raw data aliased as EEPROMFT232H.
func (e *EEPROM) AsFT232H() *EEPROMFT232H {
// sizeof(EEPROMFT232H)
if len(e.Raw) < 44 {
return nil
}
return (*EEPROMFT232H)(unsafe.Pointer(&e.Raw[0]))
}
// AsFT2232H returns the Raw data aliased as EEPROMFT2232H.
func (e *EEPROM) AsFT2232H() *EEPROMFT2232H {
// sizeof(EEPROMFT2232H)
if len(e.Raw) < 40 {
return nil
}
return (*EEPROMFT2232H)(unsafe.Pointer(&e.Raw[0]))
}
// AsFT232R returns the Raw data aliased as EEPROMFT232R.
func (e *EEPROM) AsFT232R() *EEPROMFT232R {
// sizeof(EEPROMFT232R)
if len(e.Raw) < 32 {
return nil
}
return (*EEPROMFT232R)(unsafe.Pointer(&e.Raw[0]))
}
// FT232hCBusMux is stored in the FT232H EEPROM to control each CBus pin.
type FT232hCBusMux uint8
const (
// TriSt-PU; Sets in Tristate (pull up) (C0~C6, C8, C9) on 75kΩ.
FT232hCBusTristatePullUp FT232hCBusMux = 0x00
// TXLED#; Pulses low when transmitting data (C0~C6, C8, C9).
FT232hCBusTxLED FT232hCBusMux = 0x01
// RXLED#; Pulses low when receiving data (C0~C6, C8, C9).
FT232hCBusRxLED FT232hCBusMux = 0x02
// TX&RXLED#; Pulses low when either receiving or transmitting data (C0~C6,
// C8, C9).
FT232hCBusTxRxLED FT232hCBusMux = 0x03
// PWREN#; Output is low after the device has been configured by USB, then
// high during USB suspend mode (C0~C6, C8, C9).
//
// Must be used with an external 10kΩ pull up.
FT232hCBusPwrEnable FT232hCBusMux = 0x04
// SLEEP#; Goes low during USB suspend mode (C0~C6, C8, C9).
FT232hCBusSleep FT232hCBusMux = 0x05
// DRIVE1; Drives pin to logic 0 (C0~C6, C8, C9).
FT232hCBusDrive0 FT232hCBusMux = 0x06
// DRIVE1; Drives pin to logic 1 (C0, C5, C6, C8, C9).
FT232hCBusDrive1 FT232hCBusMux = 0x07
// I/O Mode; CBus bit-bang mode option (C5, C6, C8, C9).
FT232hCBusIOMode FT232hCBusMux = 0x08
// TXDEN; Tx Data Enable. Used with RS485 level converters to enable the line
// driver during data transmit. It is active one bit time before the start
// bit up to until the end of the stop bit (C0~C6, C8, C9).
FT232hCBusTxdEnable FT232hCBusMux = 0x09
// CLK30 30MHz clock output (C0, C5, C6, C8, C9).
FT232hCBusClk30 FT232hCBusMux = 0x0A
// CLK15 15MHz clock output (C0, C5, C6, C8, C9).
FT232hCBusClk15 FT232hCBusMux = 0x0B
// CLK7.5 7.5MHz clock output (C0, C5, C6, C8, C9).
FT232hCBusClk7_5 FT232hCBusMux = 0x0C
)
const ft232hCBusMuxName = "FT232hCBusTristatePullUpFT232hCBusTxLEDFT232hCBusRxLEDFT232hCBusTxRxLEDFT232hCBusPwrEnableFT232hCBusSleepFT232hCBusDrive0FT232hCBusDrive1FT232hCBusIOModeFT232hCBusTxdEnableFT232hCBusClk30FT232hCBusClk15FT232hCBusClk7_5"
var fr232hCBusMuxIndex = [...]uint8{0, 24, 39, 54, 71, 90, 105, 121, 137, 153, 172, 187, 202, 218}
func (f FT232hCBusMux) String() string {
if f >= FT232hCBusMux(len(fr232hCBusMuxIndex)-1) {
return fmt.Sprintf("FT232hCBusMux(%d)", f)
}
return ft232hCBusMuxName[fr232hCBusMuxIndex[f]:fr232hCBusMuxIndex[f+1]]
}
// FT232rCBusMux is stored in the FT232R EEPROM to control each CBus pin.
type FT232rCBusMux uint8
const (
// TXDEN; Tx Data Enable. Used with RS485 level converters to enable the line
// driver during data transmit. It is active one bit time before the start
// bit up to until the end of the stop bit (C0~C4).
FT232rCBusTxdEnable FT232rCBusMux = 0x00
// PWREN#; Output is low after the device has been configured by USB, then
// high during USB suspend mode (C0~C4).
//
// Must be used with an external 10kΩ pull up.
FT232rCBusPwrEnable FT232rCBusMux = 0x01
// RXLED#; Pulses low when receiving data (C0~C4).
FT232rCBusRxLED FT232rCBusMux = 0x02
// TXLED#; Pulses low when transmitting data (C0~C4).
FT232rCBusTxLED FT232rCBusMux = 0x03
// TX&RXLED#; Pulses low when either receiving or transmitting data (C0~C4).
FT232rCBusTxRxLED FT232rCBusMux = 0x04
// SLEEP# Goes low during USB suspend mode (C0~C4).
FT232rCBusSleep FT232rCBusMux = 0x05
// CLK48 48Mhz +/-0.7% clock output (C0~C4).
FT232rCBusClk48 FT232rCBusMux = 0x06
// CLK24 24Mhz clock output (C0~C4).
FT232rCBusClk24 FT232rCBusMux = 0x07
// CLK12 12Mhz clock output (C0~C4).
FT232rCBusClk12 FT232rCBusMux = 0x08
// CLK6 6Mhz +/-0.7% clock output (C0~C4).
FT232rCBusClk6 FT232rCBusMux = 0x09
// CBitBangI/O; CBus bit-bang mode option (C0~C3).
FT232rCBusIOMode FT232rCBusMux = 0x0A
// BitBangWRn; CBus WR# strobe output (C0~C3).
FT232rCBusBitBangWR FT232rCBusMux = 0x0B
// BitBangRDn; CBus RD# strobe output (C0~C3).
FT232rCBusBitBangRD FT232rCBusMux = 0x0C
)
const ft232rCBusMuxName = "FT232rCBusTxdEnableFT232rCBusPwrEnableFT232rCBusRxLEDFT232rCBusTxLEDFT232rCBusTxRxLEDFT232rCBusSleepFT232rCBusClk48FT232rCBusClk24FT232rCBusClk12FT232rCBusClk6FT232rCBusIOModeFT232rCBusBitBangWRFT232rCBusBitBangRD"
var ft232rCBusMuxIndex = [...]uint8{0, 19, 38, 53, 68, 85, 100, 115, 130, 145, 159, 175, 194, 213}
func (f FT232rCBusMux) String() string {
if f >= FT232rCBusMux(len(ft232rCBusMuxIndex)-1) {
return fmt.Sprintf("FT232rCBusMux(%d)", f)
}
return ft232rCBusMuxName[ft232rCBusMuxIndex[f]:ft232rCBusMuxIndex[f+1]]
}
// EEPROMHeader is the common header found on FTDI devices.
//
// It is 16 bytes long.
type EEPROMHeader struct {
DeviceType DevType // 0x00 FTxxxx device type to be programmed
VendorID uint16 // 0x04 Defaults to 0x0403; can be changed
ProductID uint16 // 0x06 Defaults to 0x6001 for FT232R, 0x6014 for FT232H, relevant value
SerNumEnable uint8 // 0x07 bool Non-zero if serial number to be used
Unused0 uint8 // 0x08 For alignment.
MaxPower uint16 // 0x0A 0mA < MaxPower <= 500mA
SelfPowered uint8 // 0x0C bool 0 = bus powered, 1 = self powered
RemoteWakeup uint8 // 0x0D bool 0 = not capable, 1 = capable; RI# low will wake host in 20ms.
PullDownEnable uint8 // 0x0E bool Non zero if pull down in suspend enabled
Unused1 uint8 // 0x0F For alignment.
}
// EEPROMFT232H is the EEPROM layout of a FT232H device.
//
// It is 44 bytes long.
type EEPROMFT232H struct {
EEPROMHeader
// FT232H specific.
ACSlowSlew uint8 // 0x10 bool Non-zero if AC bus pins have slow slew
ACSchmittInput uint8 // 0x11 bool Non-zero if AC bus pins are Schmitt input
ACDriveCurrent uint8 // 0x12 Valid values are 4mA, 8mA, 12mA, 16mA in 2mA units
ADSlowSlew uint8 // 0x13 bool Non-zero if AD bus pins have slow slew
ADSchmittInput uint8 // 0x14 bool Non-zero if AD bus pins are Schmitt input
ADDriveCurrent uint8 // 0x15 Valid values are 4mA, 8mA, 12mA, 16mA in 2mA units
Cbus0 FT232hCBusMux // 0x16
Cbus1 FT232hCBusMux // 0x17
Cbus2 FT232hCBusMux // 0x18
Cbus3 FT232hCBusMux // 0x19
Cbus4 FT232hCBusMux // 0x1A
Cbus5 FT232hCBusMux // 0x1B
Cbus6 FT232hCBusMux // 0x1C
Cbus7 FT232hCBusMux // 0x1D C7 is limited a sit can only do 'suspend on C7 low'. Defaults pull down.
Cbus8 FT232hCBusMux // 0x1E
Cbus9 FT232hCBusMux // 0x1F
FT1248Cpol uint8 // 0x20 bool FT1248 clock polarity - clock idle high (true) or clock idle low (false)
FT1248Lsb uint8 // 0x21 bool FT1248 data is LSB (true), or MSB (false)
FT1248FlowControl uint8 // 0x22 bool FT1248 flow control enable
IsFifo uint8 // 0x23 bool Non-zero if Interface is 245 FIFO
IsFifoTar uint8 // 0x24 bool Non-zero if Interface is 245 FIFO CPU target
IsFastSer uint8 // 0x25 bool Non-zero if Interface is Fast serial
IsFT1248 uint8 // 0x26 bool Non-zero if Interface is FT1248
PowerSaveEnable uint8 // 0x27 bool Suspect on ACBus7 low.
DriverType uint8 // 0x28 bool 0 is D2XX, 1 is VCP
Unused2 uint8 // 0x29
Unused3 uint16 // 0x30
}
func (e *EEPROMFT232H) Defaults() {
// As found on Adafruit device.
e.ACDriveCurrent = 4
e.ADDriveCurrent = 4
e.Cbus0 = FT232hCBusTristatePullUp
e.Cbus1 = FT232hCBusTristatePullUp
e.Cbus2 = FT232hCBusTristatePullUp
e.Cbus3 = FT232hCBusTristatePullUp
e.Cbus4 = FT232hCBusTristatePullUp
e.Cbus5 = FT232hCBusTristatePullUp
e.Cbus6 = FT232hCBusTristatePullUp
e.Cbus7 = FT232hCBusTristatePullUp
e.Cbus8 = FT232hCBusDrive1
e.Cbus9 = FT232hCBusDrive0
}
// EEPROMFT2232H is the EEPROM layout of a FT2232H device.
//
// It is 40 bytes long.
type EEPROMFT2232H struct {
EEPROMHeader
// FT232H specific.
ALSlowSlew uint8 // 0x10 bool non-zero if AL pins have slow slew
ALSchmittInput uint8 // 0x11 bool non-zero if AL pins are Schmitt input
ALDriveCurrent uint8 // 0x12 Valid values are 4mA, 8mA, 12mA, 16mA in 2mA units
AHSlowSlew uint8 // 0x13 bool non-zero if AH pins have slow slew
AHSchmittInput uint8 // 0x14 bool non-zero if AH pins are Schmitt input
AHDriveCurrent uint8 // 0x15 Valid values are 4mA, 8mA, 12mA, 16mA in 2mA units
BLSlowSlew uint8 // 0x16 bool non-zero if BL pins have slow slew
BLSchmittInput uint8 // 0x17 bool non-zero if BL pins are Schmitt input
BLDriveCurrent uint8 // 0x18 Valid values are 4mA, 8mA, 12mA, 16mA in 2mA units
BHSlowSlew uint8 // 0x19 bool non-zero if BH pins have slow slew
BHSchmittInput uint8 // 0x1A bool non-zero if BH pins are Schmitt input
BHDriveCurrent uint8 // 0x1B Valid values are 4mA, 8mA, 12mA, 16mA in 2mA units
AIsFifo uint8 // 0x1C bool non-zero if interface is 245 FIFO
AIsFifoTar uint8 // 0x1D bool non-zero if interface is 245 FIFO CPU target
AIsFastSer uint8 // 0x1E bool non-zero if interface is Fast serial
BIsFifo uint8 // 0x1F bool non-zero if interface is 245 FIFO
BIsFifoTar uint8 // 0x20 bool non-zero if interface is 245 FIFO CPU target
BIsFastSer uint8 // 0x21 bool non-zero if interface is Fast serial
PowerSaveEnable uint8 // 0x22 bool non-zero if using BCBUS7 to save power for self-powered designs
ADriverType uint8 // 0x23 bool
BDriverType uint8 // 0x24 bool
Unused2 uint8 // 0x25
Unused3 uint16 // 0x26
}
// EEPROMFT232R is the EEPROM layout of a FT232R device.
//
// It is 32 bytes long.
type EEPROMFT232R struct {
EEPROMHeader
// FT232R specific.
IsHighCurrent uint8 // 0x10 bool High Drive I/Os; 3mA instead of 1mA (@3.3V)
UseExtOsc uint8 // 0x11 bool Use external oscillator
InvertTXD uint8 // 0x12 bool
InvertRXD uint8 // 0x13 bool
InvertRTS uint8 // 0x14 bool
InvertCTS uint8 // 0x15 bool
InvertDTR uint8 // 0x16 bool
InvertDSR uint8 // 0x17 bool
InvertDCD uint8 // 0x18 bool
InvertRI uint8 // 0x19 bool
Cbus0 FT232rCBusMux // 0x1A Default ft232rCBusTxLED
Cbus1 FT232rCBusMux // 0x1B Default ft232rCBusRxLED
Cbus2 FT232rCBusMux // 0x1C Default ft232rCBusTxdEnable
Cbus3 FT232rCBusMux // 0x1D Default ft232rCBusPwrEnable
Cbus4 FT232rCBusMux // 0x1E Default ft232rCBusSleep
DriverType uint8 // 0x1F bool 0 is D2XX, 1 is VCP
}
func (e *EEPROMFT232R) Defaults() {
// As found on Adafruit device.
e.Cbus0 = FT232rCBusTxLED
e.Cbus1 = FT232rCBusRxLED
e.Cbus2 = FT232rCBusTxdEnable
e.Cbus3 = FT232rCBusPwrEnable
e.Cbus4 = FT232rCBusSleep
e.DriverType = 1
}
//
// DevType is the FTDI device type.
type DevType uint32
const (
DevTypeFTBM DevType = iota // 0
DevTypeFTAM
DevTypeFT100AX
DevTypeUnknown // 3
DevTypeFT2232C
DevTypeFT232R // 5
DevTypeFT2232H
DevTypeFT4232H
DevTypeFT232H // 8
DevTypeFTXSeries
DevTypeFT4222H0
DevTypeFT4222H1_2
DevTypeFT4222H3
DevTypeFT4222Prog
DevTypeFT900
DevTypeFT930
DevTypeFTUMFTPD3A
)
// EEPROMSize returns the size of the EEPROM for this device.
func (d DevType) EEPROMSize() int {
switch d {
case DevTypeFT232H:
// sizeof(EEPROMFT232H)
return 44
case DevTypeFT2232H:
// sizeof(EEPROMFT2232H)
return 40
case DevTypeFT232R:
// sizeof(EEPROMFT232R)
return 32
default:
return 256
}
}
const devTypeName = "FTBMFTAMFT100AXUnknownFT2232CFT232RFT2232HFT4232HFT232HFTXSeriesFT4222H0FT4222H1/2FT4222H3FT4222ProgFT900FT930FTUMFTPD3A"
var devTypeIndex = [...]uint8{0, 4, 8, 15, 22, 29, 35, 42, 49, 55, 64, 72, 82, 90, 100, 105, 110, 120}
func (d DevType) String() string {
if d >= DevType(len(devTypeIndex)-1) {
d = DevTypeUnknown
}
return devTypeName[devTypeIndex[d]:devTypeIndex[d+1]]
}

5
vendor/periph.io/x/host/v3/ftdi/ftdi.go generated vendored Normal file
View File

@ -0,0 +1,5 @@
// Copyright 2021 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 ftdi

241
vendor/periph.io/x/host/v3/ftdi/gpio.go generated vendored Normal file
View File

@ -0,0 +1,241 @@
// 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.
// Emulate independent GPIOs.
package ftdi
import (
"errors"
"time"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/physic"
)
// dbusSync is the handler of a synchronous bitbang on DBus.
//
// More details at:
// http://www.ftdichip.com/Support/Documents/AppNotes/AN_232R-01_Bit_Bang_Mode_Available_For_FT232R_and_Ft245R.pdf
type dbusSync interface {
dbusSyncGPIOFunc(n int) string
dbusSyncGPIOIn(n int) error
dbusSyncGPIORead(n int) gpio.Level
dbusSyncGPIOOut(n int, l gpio.Level) error
}
// dbusPinSync represents a GPIO on a synchronous bitbang DBus.
//
// It is immutable and stateless.
type dbusPinSync struct {
n string
num int
bus dbusSync
}
// String implements conn.Resource.
func (s *dbusPinSync) String() string {
return s.n
}
// Halt implements conn.Resource.
func (s *dbusPinSync) Halt() error {
return nil
}
// Name implements pin.Pin.
func (s *dbusPinSync) Name() string {
return s.n
}
// Number implements pin.Pin.
func (s *dbusPinSync) Number() int {
return s.num
}
// Function implements pin.Pin.
func (s *dbusPinSync) Function() string {
return s.bus.dbusSyncGPIOFunc(s.num)
}
// In implements gpio.PinIn.
func (s *dbusPinSync) In(pull gpio.Pull, e gpio.Edge) error {
if e != gpio.NoEdge {
// We could support it on D5.
return errors.New("d2xx: edge triggering is not supported")
}
if pull != gpio.PullUp && pull != gpio.PullNoChange {
// EEPROM has a PullDownEnable flag.
return errors.New("d2xx: pull is not supported")
}
return s.bus.dbusSyncGPIOIn(s.num)
}
// Read implements gpio.PinIn.
func (s *dbusPinSync) Read() gpio.Level {
return s.bus.dbusSyncGPIORead(s.num)
}
// WaitForEdge implements gpio.PinIn.
func (s *dbusPinSync) WaitForEdge(t time.Duration) bool {
return false
}
// DefaultPull implements gpio.PinIn.
func (s *dbusPinSync) DefaultPull() gpio.Pull {
// 200kΩ
// http://www.ftdichip.com/Support/Documents/DataSheets/ICs/DS_FT232R.pdf
// p. 24
return gpio.PullUp
}
// Pull implements gpio.PinIn.
func (s *dbusPinSync) Pull() gpio.Pull {
return gpio.PullUp
}
// Out implements gpio.PinOut.
func (s *dbusPinSync) Out(l gpio.Level) error {
return s.bus.dbusSyncGPIOOut(s.num, l)
}
// PWM implements gpio.PinOut.
func (s *dbusPinSync) PWM(d gpio.Duty, f physic.Frequency) error {
return errors.New("d2xx: not implemented")
}
/*
func (s *dbusPinSync) Drive() physic.ElectricCurrent {
// optionally 3
//return s.bus.ee.DDriveCurrent * physic.MilliAmpere
return physic.MilliAmpere
}
func (s *dbusPinSync) SlewLimit() bool {
//return s.bus.ee.DSlowSlew
return false
}
func (s *dbusPinSync) Hysteresis() bool {
//return s.bus.ee.DSchmittInput
return true
}
*/
//
// cBusGPIO is the handler of a CBus bitbang bus.
//
// This is an asynchronous mode.
//
// More details at:
// http://www.ftdichip.com/Support/Knowledgebase/index.html?cbusbitbangmode.htm
type cBusGPIO interface {
cBusGPIOFunc(n int) string
cBusGPIOIn(n int) error
cBusGPIORead(n int) gpio.Level
cBusGPIOOut(n int, l gpio.Level) error
}
// cbusPin represents a GPIO on a CBus bitbang bus.
//
// It is immutable and stateless.
type cbusPin struct {
n string
num int
p gpio.Pull
bus cBusGPIO
}
// String implements conn.Resource.
func (c *cbusPin) String() string {
return c.n
}
// Halt implements conn.Resource.
func (c *cbusPin) Halt() error {
return nil
}
// Name implements pin.Pin.
func (c *cbusPin) Name() string {
return c.n
}
// Number implements pin.Pin.
func (c *cbusPin) Number() int {
return c.num
}
// Function implements pin.Pin.
func (c *cbusPin) Function() string {
return c.bus.cBusGPIOFunc(c.num)
}
// In implements gpio.PinIn.
func (c *cbusPin) In(pull gpio.Pull, e gpio.Edge) error {
if e != gpio.NoEdge {
// We could support it on D5.
return errors.New("d2xx: edge triggering is not supported")
}
if pull != c.p && pull != gpio.PullNoChange {
// EEPROM has a PullDownEnable flag.
return errors.New("d2xx: pull is not supported")
}
return c.bus.cBusGPIOIn(c.num)
}
// Read implements gpio.PinIn.
func (c *cbusPin) Read() gpio.Level {
return c.bus.cBusGPIORead(c.num)
}
// WaitForEdge implements gpio.PinIn.
func (c *cbusPin) WaitForEdge(t time.Duration) bool {
return false
}
// DefaultPull implements gpio.PinIn.
func (c *cbusPin) DefaultPull() gpio.Pull {
// 200kΩ
// http://www.ftdichip.com/Support/Documents/DataSheets/ICs/DS_FT232R.pdf
// p. 24
return c.p
}
// Pull implements gpio.PinIn.
func (c *cbusPin) Pull() gpio.Pull {
return c.p
}
// Out implements gpio.PinOut.
func (c *cbusPin) Out(l gpio.Level) error {
return c.bus.cBusGPIOOut(c.num, l)
}
// PWM implements gpio.PinOut.
func (c *cbusPin) PWM(d gpio.Duty, f physic.Frequency) error {
return errors.New("d2xx: not implemented")
}
/*
func (c *cbusPin) Drive() physic.ElectricCurrent {
// optionally 3
//return c.bus.ee.CDriveCurrent * physic.MilliAmpere
return physic.MilliAmpere
}
func (c *cbusPin) SlewLimit() bool {
//return c.bus.ee.CSlowSlew
return false
}
func (c *cbusPin) Hysteresis() bool {
//return c.bus.ee.CSchmittInput
return true
}
*/
var _ gpio.PinIO = &dbusPinSync{}
var _ gpio.PinIO = &cbusPin{}

382
vendor/periph.io/x/host/v3/ftdi/handle.go generated vendored Normal file
View File

@ -0,0 +1,382 @@
// Copyright 2021 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 ftdi
import (
"context"
"errors"
"fmt"
"io"
"periph.io/x/conn/v3/physic"
"periph.io/x/d2xx"
)
//
// bitMode is used by SetBitMode to change the chip behavior.
type bitMode uint8
const (
// Resets all Pins to their default value
bitModeReset bitMode = 0x00
// Sets the DBus to asynchronous bit-bang.
bitModeAsyncBitbang bitMode = 0x01
// Switch to MPSSE mode (FT2232, FT2232H, FT4232H and FT232H).
bitModeMpsse bitMode = 0x02
// Sets the DBus to synchronous bit-bang (FT232R, FT245R, FT2232, FT2232H,
// FT4232H and FT232H).
bitModeSyncBitbang bitMode = 0x04
// Switch to MCU host bus emulation (FT2232, FT2232H, FT4232H and FT232H).
bitModeMcuHost bitMode = 0x08
// Switch to fast opto-isolated serial mode (FT2232, FT2232H, FT4232H and
// FT232H).
bitModeFastSerial bitMode = 0x10
// Sets the CBus in 4 bits bit-bang mode (FT232R and FT232H)
// In this case, upper nibble controls which pin is output/input, lower
// controls which of outputs are high and low.
bitModeCbusBitbang bitMode = 0x20
// Single Channel Synchronous 245 FIFO mode (FT2232H and FT232H).
bitModeSyncFifo bitMode = 0x40
)
// numDevices returns the number of detected devices.
func numDevices() (int, error) {
num, e := d2xx.CreateDeviceInfoList()
if e != 0 {
return 0, toErr("GetNumDevices initialization failed", e)
}
return num, nil
}
func openHandle(opener func(i int) (d2xx.Handle, d2xx.Err), i int) (*handle, error) {
h, e := opener(i)
if e != 0 {
return nil, toErr("Open", e)
}
d := &handle{h: h}
t, vid, did, e := h.GetDeviceInfo()
if e != 0 {
_ = d.Close()
return nil, toErr("GetDeviceInfo", e)
}
d.t = DevType(t)
d.venID = vid
d.devID = did
return d, nil
}
// handle is a thin wrapper around the low level d2xx device handle to make it
// more go-idiomatic.
//
// It also implements many utility functions to help with initialization and
// device management.
type handle struct {
// It is just above 'handle' which directly maps to D2XX function calls.
//
// Dev converts the int error type into Go native error and handles higher
// level functionality like reading and writing to the USB connection.
//
// The content of the struct is immutable after initialization.
h d2xx.Handle
t DevType
venID uint16
devID uint16
}
func (h *handle) Close() error {
// Not yet called.
return toErr("Close", h.h.Close())
}
// Init is the general setup for common devices.
//
// It tries first the 'happy path' which doesn't reset the device. By doing so,
// the goal is to reduce the amount of glitches on the GPIO pins, on a best
// effort basis. On all devices, the GPIOs are still reset as inputs, since
// there is no way to determine if each GPIO is an input or output.
func (h *handle) Init() error {
// Driver: maximum packet size. Note that this clears any data in the buffer,
// so it is good to do it immediately after a reset. The 'out' parameter is
// ignored.
// TODO(maruel): The FT232H doc claims a 512 byte packets support in hi-speed
// mode, which means that this would likely be better to use this value.
if e := h.h.SetUSBParameters(65536, 0); e != 0 {
return toErr("SetUSBParameters", e)
}
// Driver: Set I/O timeouts to 15 sec. The reason is that we want the
// timeouts to be very visible, at least as the driver is being developed.
if e := h.h.SetTimeouts(15000, 15000); e != 0 {
return toErr("SetTimeouts", e)
}
// Not sure: Disable event/error characters.
if e := h.h.SetChars(0, false, 0, false); e != 0 {
return toErr("SetChars", e)
}
// Not sure: Latency timer at 1ms.
if e := h.h.SetLatencyTimer(1); e != 0 {
return toErr("SetLatencyTimer", e)
}
// Not sure: Turn on flow control to synchronize IN requests.
if e := h.h.SetFlowControl(); e != 0 {
return toErr("SetFlowControl", e)
}
// Just in case. It's a very small cost.
return h.Flush()
}
// Reset resets the device.
func (h *handle) Reset() error {
if e := h.h.ResetDevice(); e != 0 {
return toErr("Reset", e)
}
if err := h.SetBitMode(0, bitModeReset); err != nil {
return err
}
// USB/driver: Flush any pending read buffer that had been sent by the device
// before it reset. Do not return any error there, as the device may spew a
// read error right after being initialized.
_ = h.Flush()
return nil
}
// GetBitMode returns the current bit mode.
//
// This is device-dependent.
func (h *handle) GetBitMode() (byte, error) {
l, e := h.h.GetBitMode()
if e != 0 {
return 0, toErr("GetBitMode", e)
}
return l, nil
}
// SetBitMode change the mode of operation of the device.
//
// mask sets which pins are inputs and outputs for bitModeCbusBitbang.
func (h *handle) SetBitMode(mask byte, mode bitMode) error {
return toErr("SetBitMode", h.h.SetBitMode(mask, byte(mode)))
}
// Flush flushes any data left in the read buffer.
func (h *handle) Flush() error {
var buf [128]byte
for {
p, err := h.Read(buf[:])
if err != nil {
return err
}
if p == 0 {
return nil
}
}
}
// Read returns as much as available in the read buffer without blocking.
func (h *handle) Read(b []byte) (int, error) {
// GetQueueStatus() 60µs is relatively slow compared to Read() 4µs,
// but surprisingly if GetQueueStatus() is *not* called, Read()
// becomes largely slower (800µs).
//
// TODO(maruel): This asks for more perf testing before settling on the best
// solution.
// TODO(maruel): Investigate FT_GetStatus().
p, e := h.h.GetQueueStatus()
if p == 0 || e != 0 {
return int(p), toErr("Read/GetQueueStatus", e)
}
v := int(p)
if v > len(b) {
v = len(b)
}
n, e := h.h.Read(b[:v])
return n, toErr("Read", e)
}
// ReadAll blocks to return all the data.
//
// Similar to ioutil.ReadAll() except that it will stop if the context is
// canceled.
func (h *handle) ReadAll(ctx context.Context, b []byte) (int, error) {
// TODO(maruel): Use FT_SetEventNotification() instead of looping when
// waiting for bytes.
for offset := 0; offset != len(b); {
if ctx.Err() != nil {
return offset, io.EOF
}
chunk := len(b) - offset
if chunk > 4096 {
chunk = 4096
}
n, err := h.Read(b[offset : offset+chunk])
if offset += n; err != nil {
return offset, err
}
}
return len(b), nil
}
// WriteFast writes to the USB device.
//
// In practice this takes at least 0.1ms, which limits the effective rate.
//
// There's no guarantee that the data is all written, so it is important to
// check the return value.
func (h *handle) WriteFast(b []byte) (int, error) {
n, e := h.h.Write(b)
return n, toErr("Write", e)
}
// Write blocks until all data is written.
func (h *handle) Write(b []byte) (int, error) {
for offset := 0; offset != len(b); {
chunk := len(b) - offset
if chunk > 4096 {
chunk = 4096
}
p, err := h.WriteFast(b[offset : offset+chunk])
if err != nil {
return offset + p, err
}
if p != 0 {
offset += p
}
}
return len(b), nil
}
// ReadEEPROM reads the EEPROM.
func (h *handle) ReadEEPROM(ee *EEPROM) error {
// The raw data size must be exactly what the device contains.
eepromSize := h.t.EEPROMSize()
if len(ee.Raw) < eepromSize {
ee.Raw = make([]byte, eepromSize)
} else if len(ee.Raw) > eepromSize {
ee.Raw = ee.Raw[:eepromSize]
}
ee2 := d2xx.EEPROM{Raw: ee.Raw}
e := h.h.EEPROMRead(uint32(h.t), &ee2)
ee.Manufacturer = ee2.Manufacturer
ee.ManufacturerID = ee2.ManufacturerID
ee.Desc = ee2.Desc
ee.Serial = ee2.Serial
if e != 0 {
// 15 == FT_EEPROM_NOT_PROGRAMMED
if e != 15 {
return toErr("EEPROMRead", e)
}
// It's a fresh new device. Devices bought via Adafruit already have
// their EEPROM programmed with Adafruit branding but fake devices sold by
// CJMCU are not. Since GetDeviceInfo() above succeeded, we know the
// device type via the USB descriptor, which is sufficient to load the
// driver, which permits to program the EEPROM to "bootstrap" it.
//
// Fill it with an empty yet valid EEPROM content. We don't want to set
// VenID or DevID to 0! Nobody would do that, right?
ee.Raw = make([]byte, h.t.EEPROMSize())
hdr := ee.AsHeader()
hdr.DeviceType = h.t
hdr.VendorID = h.venID
hdr.ProductID = h.devID
}
return nil
}
// WriteEEPROM programs the EEPROM.
func (h *handle) WriteEEPROM(ee *EEPROM) error {
if err := ee.Validate(); err != nil {
return err
}
if len(ee.Raw) != 0 {
hdr := ee.AsHeader()
if hdr == nil {
return errors.New("ftdi: unexpected EEPROM header size")
}
if hdr.DeviceType != h.t {
return errors.New("ftdi: unexpected device type set while programming EEPROM")
}
if hdr.VendorID != h.venID {
return errors.New("ftdi: unexpected VenID set while programming EEPROM")
}
if hdr.ProductID != h.devID {
return errors.New("ftdi: unexpected DevID set while programming EEPROM")
}
}
ee2 := d2xx.EEPROM{
Raw: ee.Raw,
Manufacturer: ee.Manufacturer,
ManufacturerID: ee.ManufacturerID,
Desc: ee.Desc,
Serial: ee.Serial,
}
return toErr("EEPROMWrite", h.h.EEPROMProgram(&ee2))
}
// EraseEEPROM erases all the EEPROM.
//
// Will fail on FT232R and FT245R.
func (h *handle) EraseEEPROM() error {
return toErr("EraseEE", h.h.EraseEE())
}
// ReadUA reads the EEPROM user area.
//
// May return nil when there's nothing programmed yet.
func (h *handle) ReadUA() ([]byte, error) {
size, e := h.h.EEUASize()
if e != 0 {
return nil, toErr("EEUASize", e)
}
if size == 0 {
// Happens on uninitialized EEPROM.
return nil, nil
}
b := make([]byte, size)
if e := h.h.EEUARead(b); e != 0 {
return nil, toErr("EEUARead", e)
}
return b, nil
}
// WriteUA writes to the EEPROM user area.
func (h *handle) WriteUA(ua []byte) error {
size, e := h.h.EEUASize()
if e != 0 {
return toErr("EEUASize", e)
}
if size == 0 {
return errors.New("ftdi: please program EEPROM first")
}
if size < len(ua) {
return fmt.Errorf("ftdi: maximum user area size is %d bytes", size)
}
if size != len(ua) {
b := make([]byte, size)
copy(b, ua)
ua = b
}
if e := h.h.EEUAWrite(ua); e != 0 {
return toErr("EEUAWrite", e)
}
return nil
}
// SetBaudRate sets the baud rate.
func (h *handle) SetBaudRate(f physic.Frequency) error {
if f >= physic.GigaHertz {
return errors.New("ftdi: baud rate too high")
}
v := uint32(f / physic.Hertz)
return toErr("SetBaudRate", h.h.SetBaudRate(v))
}
//
func toErr(s string, e d2xx.Err) error {
if e == 0 {
return nil
}
return errors.New("ftdi: " + s + ": " + e.String())
}

295
vendor/periph.io/x/host/v3/ftdi/i2c.go generated vendored Normal file
View File

@ -0,0 +1,295 @@
// 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.
// This functionality requires MPSSE.
//
// Interfacing I²C:
// http://www.ftdichip.com/Support/Documents/AppNotes/AN_113_FTDI_Hi_Speed_USB_To_I2C_Example.pdf
//
// Implementation based on
// http://www.ftdichip.com/Support/Documents/AppNotes/AN_255_USB%20to%20I2C%20Example%20using%20the%20FT232H%20and%20FT201X%20devices.pdf
//
// Page 18: MPSSE does not automatically support clock stretching for I²C.
package ftdi
import (
"context"
"errors"
"fmt"
"periph.io/x/conn/v3"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/i2c"
"periph.io/x/conn/v3/physic"
)
const i2cSCL = 1 // D0
const i2cSDAOut = 2 // D1
const i2cSDAIn = 4 // D2
type i2cBus struct {
f *FT232H
pullUp bool
}
// Close stops I²C mode, returns to high speed mode, disable tri-state.
func (d *i2cBus) Close() error {
d.f.mu.Lock()
err := d.stopI2C()
d.f.mu.Unlock()
return err
}
// Duplex implements conn.Conn.
func (d *i2cBus) Duplex() conn.Duplex {
return conn.Half
}
func (d *i2cBus) String() string {
return d.f.String()
}
// SetSpeed implements i2c.Bus.
func (d *i2cBus) SetSpeed(f physic.Frequency) error {
if f > 10*physic.MegaHertz {
return fmt.Errorf("d2xx: invalid speed %s; maximum supported clock is 10MHz", f)
}
if f < 100*physic.Hertz {
return fmt.Errorf("d2xx: invalid speed %s; minimum supported clock is 100Hz; did you forget to multiply by physic.KiloHertz?", f)
}
d.f.mu.Lock()
defer d.f.mu.Unlock()
_, err := d.f.h.MPSSEClock(f * 2 / 3)
return err
}
// Tx implements i2c.Bus.
func (d *i2cBus) Tx(addr uint16, w, r []byte) error {
d.f.mu.Lock()
defer d.f.mu.Unlock()
if err := d.setI2CStart(); err != nil {
return err
}
a := [1]byte{byte(addr)}
if err := d.writeBytes(a[:]); err != nil {
return err
}
if len(w) != 0 {
if err := d.writeBytes(w); err != nil {
return err
}
}
if len(r) != 0 {
if err := d.readBytes(r); err != nil {
return err
}
}
if err := d.setI2CStop(); err != nil {
return err
}
return d.setI2CLinesIdle()
}
// SCL implements i2c.Pins.
func (d *i2cBus) SCL() gpio.PinIO {
return d.f.D0
}
// SDA implements i2c.Pins.
func (d *i2cBus) SDA() gpio.PinIO {
return d.f.D1
}
// setupI2C initializes the MPSSE to the state to run an I²C transaction.
//
// Defaults to 400kHz.
//
// When pullUp is true; output alternates between Out(Low) and In(PullUp).
//
// when pullUp is false; pins are set in Tristate so Out(High) becomes float
// instead of drive High. Low still drives low. That's called open collector.
func (d *i2cBus) setupI2C(pullUp bool) error {
if pullUp {
return errors.New("d2xx: PullUp will soon be implemented")
}
// TODO(maruel): We could set these only *during* the I²C operation, which
// would make more sense.
f := 400 * physic.KiloHertz
clk := ((30 * physic.MegaHertz / f) - 1) * 2 / 3
buf := [4 + 3]byte{
clock3Phase,
clock30MHz, byte(clk), byte(clk >> 8),
}
cmd := buf[:4]
if !d.pullUp {
// TODO(maruel): Do not mess with other GPIOs tristate.
cmd = append(cmd, dataTristate, 7, 0)
}
if _, err := d.f.h.Write(cmd); err != nil {
return err
}
d.f.usingI2C = true
d.pullUp = pullUp
return d.setI2CLinesIdle()
}
// stopI2C resets the MPSSE to a more "normal" state.
func (d *i2cBus) stopI2C() error {
// Resets to 30MHz.
buf := [4 + 3]byte{
clock2Phase,
clock30MHz, 0, 0,
}
cmd := buf[:4]
if !d.pullUp {
// TODO(maruel): Do not mess with other GPIOs tristate.
cmd = append(cmd, dataTristate, 0, 0)
}
_, err := d.f.h.Write(cmd)
d.f.usingI2C = false
return err
}
// setI2CLinesIdle sets all D0 and D1 lines high.
//
// Does not touch D3~D7.
func (d *i2cBus) setI2CLinesIdle() error {
const mask = 0xFF &^ (i2cSCL | i2cSDAOut | i2cSDAIn)
// TODO(maruel): d.pullUp
d.f.dbus.direction = d.f.dbus.direction&mask | i2cSCL | i2cSDAOut
d.f.dbus.value = d.f.dbus.value & mask
cmd := [...]byte{gpioSetD, d.f.dbus.value | i2cSCL | i2cSDAOut, d.f.dbus.direction}
_, err := d.f.h.Write(cmd[:])
return err
}
// setI2CStart starts an I²C transaction.
//
// Does not touch D3~D7.
func (d *i2cBus) setI2CStart() error {
// TODO(maruel): d.pullUp
dir := d.f.dbus.direction
v := d.f.dbus.value
// Assumes last setup was d.setI2CLinesIdle(), e.g. D0 and D1 are high, so
// skip this.
//
// Runs the command 4 times as a way to delay execution.
cmd := [...]byte{
// SCL high, SDA low for 600ns
gpioSetD, v | i2cSCL, dir,
gpioSetD, v | i2cSCL, dir,
gpioSetD, v | i2cSCL, dir,
gpioSetD, v | i2cSCL, dir,
// SCL low, SDA low
gpioSetD, v, dir,
gpioSetD, v, dir,
gpioSetD, v, dir,
}
_, err := d.f.h.Write(cmd[:])
return err
}
// setI2CStop completes an I²C transaction.
//
// Does not touch D3~D7.
func (d *i2cBus) setI2CStop() error {
// TODO(maruel): d.pullUp
dir := d.f.dbus.direction
v := d.f.dbus.value
// Runs the command 4 times as a way to delay execution.
cmd := [...]byte{
// SCL low, SDA low
gpioSetD, v, dir,
gpioSetD, v, dir,
gpioSetD, v, dir,
gpioSetD, v, dir,
// SCL high, SDA low
gpioSetD, v | i2cSCL, dir,
gpioSetD, v | i2cSCL, dir,
gpioSetD, v | i2cSCL, dir,
gpioSetD, v | i2cSCL, dir,
// SCL high, SDA high
gpioSetD, v | i2cSCL | i2cSDAOut, dir,
gpioSetD, v | i2cSCL | i2cSDAOut, dir,
gpioSetD, v | i2cSCL | i2cSDAOut, dir,
gpioSetD, v | i2cSCL | i2cSDAOut, dir,
}
_, err := d.f.h.Write(cmd[:])
return err
}
// writeBytes writes multiple bytes within an I²C transaction.
//
// Does not touch D3~D7.
func (d *i2cBus) writeBytes(w []byte) error {
// TODO(maruel): d.pullUp
dir := d.f.dbus.direction
v := d.f.dbus.value
// TODO(maruel): WAT?
if err := d.f.h.Flush(); err != nil {
return err
}
// TODO(maruel): Implement both with and without NAK check.
var r [1]byte
cmd := [...]byte{
// Data out, the 0 will be replaced with the byte.
dataOut | dataOutFall, 0, 0, 0,
// Set back to idle.
gpioSetD, v | i2cSCL | i2cSDAOut, dir,
// Read ACK/NAK.
dataIn | dataBit, 0,
flush,
}
for _, c := range w {
cmd[3] = c
if _, err := d.f.h.Write(cmd[:]); err != nil {
return err
}
if _, err := d.f.h.ReadAll(context.Background(), r[:]); err != nil {
return err
}
if r[0]&1 == 0 {
return errors.New("got NAK")
}
}
return nil
}
// readBytes reads multiple bytes within an I²C transaction.
//
// Does not touch D3~D7.
func (d *i2cBus) readBytes(r []byte) error {
// TODO(maruel): d.pullUp
dir := d.f.dbus.direction
v := d.f.dbus.value
cmd := [...]byte{
// Read 8 bits.
dataIn | dataBit, 7,
// Send ACK/NAK.
dataOut | dataOutFall | dataBit, 0, 0,
// Set back to idle.
gpioSetD, v | i2cSCL | i2cSDAOut, dir,
// Force read buffer flush. This is only necessary if NAK are not ignored.
flush,
}
for i := range r {
if i == len(r)-1 {
// NAK.
cmd[4] = 0x80
}
if _, err := d.f.h.Write(cmd[:]); err != nil {
return err
}
if _, err := d.f.h.ReadAll(context.Background(), r[i:1]); err != nil {
return err
}
}
return nil
}
var _ i2c.BusCloser = &i2cBus{}
var _ i2c.Pins = &i2cBus{}

452
vendor/periph.io/x/host/v3/ftdi/mpsse.go generated vendored Normal file
View File

@ -0,0 +1,452 @@
// 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.
// MPSSE is Multi-Protocol Synchronous Serial Engine
//
// MPSSE basics:
// http://www.ftdichip.com/Support/Documents/AppNotes/AN_135_MPSSE_Basics.pdf
//
// MPSSE and MCU emulation modes:
// http://www.ftdichip.com/Support/Documents/AppNotes/AN_108_Command_Processor_for_MPSSE_and_MCU_Host_Bus_Emulation_Modes.pdf
package ftdi
import (
"context"
"errors"
"fmt"
"time"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/physic"
)
const (
// TDI/TDO serial operation synchronised on clock edges.
//
// Long streams (default):
// - [1, 65536] bytes (length is sent minus one, requires 8 bits multiple)
// <op>, <LengthLow-1>, <LengthHigh-1>, <byte0>, ..., <byteN>
//
// Short streams (dataBit is specified):
// - [1, 8] bits
// <op>, <Length-1>, <byte>
//
// When both dataOut and dataIn are specified, one of dataOutFall or
// dataInFall should be specified, at least for most sane protocols.
//
// Flags:
dataOut byte = 0x10 // Enable output, default on +VE (Rise)
dataIn byte = 0x20 // Enable input, default on +VE (Rise)
dataOutFall byte = 0x01 // instead of Rise
dataInFall byte = 0x04 // instead of Rise
dataLSBF byte = 0x08 // instead of MSBF
dataBit byte = 0x02 // instead of Byte
// Data line drives low when the data is 0 and tristates on data 1. This is
// used with I²C.
// <op>, <ADBus pins>, <ACBus pins>
dataTristate byte = 0x9E
// TSM operation (for JTAG).
//
// - Send bits 6 to 0 to the TMS pin using LSB or MSB.
// - Bit 7 is passed to TDI/DO before the first clock of TMS and is held
// static for the duration of TMS clocking.
//
// <op>, <Length>, <byte>
tmsOutLSBFRise byte = 0x4A
tmsOutLSBFFall byte = 0x4B
tmsIOLSBInRise byte = 0x6A
tmsIOLSBInFall byte = 0x6B
// Unclear: 0x6E and 0x6F
// GPIO operation.
//
// - Operates on 8 GPIOs at a time, e.g. C0~C7 or D0~D7.
// - Direction 1 means output, 0 means input.
//
// <op>, <value>, <direction>
gpioSetD byte = 0x80
gpioSetC byte = 0x82
// <op>, returns <value>
gpioReadD byte = 0x81
gpioReadC byte = 0x83
// Internal loopback.
//
// Connects TDI and TDO together.
internalLoopbackEnable byte = 0x84
internalLoopbackDisable byte = 0x85
// Clock.
//
// The TCK/SK has a 50% duty cycle.
//
// The inactive clock state can be set via the gpioSetD command and control
// bit 0.
//
// By default, the base clock is 6MHz via a 5x divisor. On
// FT232H/FT2232H/FT4232H, the 5x divisor can be disabled.
clock30MHz byte = 0x8A
clock6MHz byte = 0x8B
// Sets clock divisor.
//
// The effective value depends if clock30MHz was sent or not.
//
// - 0(1) 6MHz / 30MHz
// - 1(2) 3MHz / 15MHz
// - 2(3) 2MHz / 10MHz
// - 3(4) 1.5MHz / 7.5MHz
// - 4(5) 1.25MHz / 6MHz
// - ...
// - 0xFFFF(65536) 91.553Hz / 457.763Hz
//
// <op>, <valueL-1>, <valueH-1>
clockSetDivisor byte = 0x86
// Uses 3 phases data clocking: data is valid on both clock edges. Needed
// for I²C.
clock3Phase byte = 0x8C
// Uses normal 2 phases data clocking.
clock2Phase byte = 0x8D
// Enables clock even while not doing any operation. Used with JTAG.
// Enables the clock between [1, 8] pulses.
// <op>, <length-1>
clockOnShort byte = 0x8E
// Enables the clock between [8, 524288] pulses in 8 multiples.
// <op>, <lengthL-1>, <lengthH-1>
clockOnLong byte = 0x8F
// Enables clock until D5 is high or low. Used with JTAG.
clockUntilHigh byte = 0x94
clockUntilLow byte = 0x95
// <op>, <lengthL-1>, <lengthH-1> in 8 multiples.
clockUntilHighLong byte = 0x9C
clockUntilLowLong byte = 0x9D
// Enables adaptive clocking. Used with JTAG.
//
// This causes the controller to wait for D7 signal state as an ACK.
clockAdaptive byte = 0x96
// Disables adaptive clocking.
clockNormal byte = 0x97
// CPU mode.
//
// Access the device registers like a memory mapped device.
//
// <op>, <addrLow>
cpuReadShort byte = 0x90
// <op>, <addrHi>, <addrLow>
cpuReadFar byte = 0x91
// <op>, <addrLow>, <data>
cpuWriteShort byte = 0x92
// <op>, <addrHi>, <addrLow>, <data>
cpuWriteFar byte = 0x91
// Buffer operations.
//
// Flush the buffer back to the host.
flush byte = 0x87
// Wait until D5 (JTAG) or I/O1 (CPU) is high. Once it is detected as
// high, the MPSSE engine moves on to process the next instruction.
waitHigh byte = 0x88
waitLow byte = 0x89
)
// InitMPSSE sets the device into MPSSE mode.
//
// This requires a f232h, ft2232, ft2232h or a ft4232h.
//
// Use only one of Init or InitMPSSE.
func (h *handle) InitMPSSE() error {
// http://www.ftdichip.com/Support/Documents/AppNotes/AN_255_USB%20to%20I2C%20Example%20using%20the%20FT232H%20and%20FT201X%20devices.pdf
// Pre-state:
// - Write EEPROM i.IsFifo = true so the device DBus is started in tristate.
// Try to verify the MPSSE controller without initializing it first. This is
// the 'happy path', which enables reusing the device is its current state
// without affecting current GPIO state.
if h.mpsseVerify() != nil {
// Do a full reset. Just trying to set the MPSSE controller will
// likely not work. That's a layering violation (since the retry with reset
// is done in driver.go) but we've survived worse things...
//
// TODO(maruel): This is not helping in practice, this need to be fine
// tuned.
if err := h.Reset(); err != nil {
return err
}
if err := h.Init(); err != nil {
return err
}
if err := h.SetBitMode(0, bitModeMpsse); err != nil {
return err
}
if err := h.mpsseVerify(); err != nil {
return err
}
}
// Initialize MPSSE to a known state.
// Reset the clock since it is impossible to read back the current clock rate.
// Reset all the GPIOs are inputs since it is impossible to read back the
// state of each GPIO (if they are input or output).
cmd := []byte{
clock30MHz, clockNormal, clock2Phase, internalLoopbackDisable,
gpioSetC, 0x00, 0x00,
gpioSetD, 0x00, 0x00,
}
if _, err := h.Write(cmd); err != nil {
return err
}
// Success!!
return nil
}
// mpsseVerify sends an invalid MPSSE command and verifies the returned value
// is incorrect.
//
// In practice this takes around 2ms.
func (h *handle) mpsseVerify() error {
var b [16]byte
for _, v := range []byte{0xAA, 0xAB} {
// Write a bad command and ensure it returned correctly.
// Unlike what the application note proposes, include a flush op right
// after. Without the flush, the device will only flush after the delay
// specified to SetLatencyTimer. The flush removes this unneeded wait,
// which enables increasing the delay specified to SetLatencyTimer.
b[0] = v
b[1] = flush
if _, err := h.Write(b[:2]); err != nil {
return fmt.Errorf("d2xx: mpsseVerify: %v", err)
}
// Sometimes, especially right after a reset, the device spews a few bytes.
// Discard them. This significantly increases the odds of a successful
// initialization.
p, e := h.h.GetQueueStatus()
if e != 0 {
return toErr("Read/GetQueueStatus", e)
}
for p > 2 {
l := int(p) - 2
if l > len(b) {
l = len(b)
}
// Discard the overflow bytes.
ctx, cancel := context200ms()
defer cancel()
if _, err := h.ReadAll(ctx, b[:l]); err != nil {
return fmt.Errorf("d2xx: mpsseVerify: %v", err)
}
p -= uint32(l)
}
// Custom implementation, as we want to flush any stray byte.
ctx, cancel := context200ms()
defer cancel()
if _, err := h.ReadAll(ctx, b[:2]); err != nil {
return fmt.Errorf("d2xx: mpsseVerify: %v", err)
}
// 0xFA means invalid command, 0xAA is the command echoed back.
if b[0] != 0xFA || b[1] != v {
return fmt.Errorf("d2xx: mpsseVerify: failed test for byte %#x: %#x", v, b)
}
}
return nil
}
//
// MPSSERegRead reads the memory mapped registers from the device.
func (h *handle) MPSSERegRead(addr uint16) (byte, error) {
// Unlike most other operations, the uint16 byte order is <hi>, <lo>.
b := [...]byte{cpuReadFar, byte(addr >> 8), byte(addr), flush}
if _, err := h.Write(b[:]); err != nil {
return 0, err
}
ctx, cancel := context200ms()
defer cancel()
_, err := h.ReadAll(ctx, b[:1])
return b[0], err
}
// MPSSEClock sets the clock at the closest value and returns it.
func (h *handle) MPSSEClock(f physic.Frequency) (physic.Frequency, error) {
// TODO(maruel): Memory clock and skip if the same value.
clk := clock30MHz
base := 30 * physic.MegaHertz
div := base / f
if div >= 65536 {
clk = clock6MHz
base /= 5
div = base / f
if div >= 65536 {
return 0, errors.New("d2xx: clock frequency is too low")
}
}
b := [...]byte{clk, clockSetDivisor, byte(div - 1), byte((div - 1) >> 8)}
_, err := h.Write(b[:])
return base / div, err
}
// mpsseTxOp returns the right MPSSE command byte for the stream.
func mpsseTxOp(w, r bool, ew, er gpio.Edge, lsbf bool) byte {
op := byte(0)
if lsbf {
op |= dataLSBF
}
if w {
op |= dataOut
if ew == gpio.FallingEdge {
op |= dataOutFall
}
}
if r {
op |= dataIn
if er == gpio.FallingEdge {
op |= dataInFall
}
}
return op
}
// MPSSETx runs a transaction on the clock on pins D0, D1 and D2.
//
// It can only do it on a multiple of 8 bits.
func (h *handle) MPSSETx(w, r []byte, ew, er gpio.Edge, lsbf bool) error {
l := len(w)
if len(w) != 0 {
// TODO(maruel): This is easy to fix by daisy chaining operations.
if len(w) > 65536 {
return errors.New("d2xx: write buffer too long; max 65536")
}
}
if len(r) != 0 {
if len(r) > 65536 {
return errors.New("d2xx: read buffer too long; max 65536")
}
if l != 0 && len(r) != l {
return errors.New("d2xx: mismatched buffer lengths")
}
l = len(r)
}
// The FT232H has 1Kb Tx and Rx buffers. So partial writes should be done.
// TODO(maruel): Test.
// Flush can be useful if rbits != 0.
op := mpsseTxOp(len(w) != 0, len(r) != 0, ew, er, lsbf)
cmd := []byte{op, byte(l - 1), byte((l - 1) >> 8)}
cmd = append(cmd, w...)
if len(r) != 0 {
cmd = append(cmd, flush)
}
if _, err := h.Write(cmd); err != nil {
return err
}
if len(r) != 0 {
ctx, cancel := context200ms()
defer cancel()
_, err := h.ReadAll(ctx, r)
return err
}
return nil
}
// MPSSETxShort runs a transaction on the clock pins D0, D1 and D2 for a byte
// or less: between 1 and 8 bits.
func (h *handle) MPSSETxShort(w byte, wbits, rbits int, ew, er gpio.Edge, lsbf bool) (byte, error) {
op := byte(dataBit)
if lsbf {
op |= dataLSBF
}
l := wbits
if wbits != 0 {
if wbits > 8 {
return 0, errors.New("d2xx: write buffer too long; max 8")
}
op |= dataOut
if ew == gpio.FallingEdge {
op |= dataOutFall
}
}
if rbits != 0 {
if rbits > 8 {
return 0, errors.New("d2xx: read buffer too long; max 8")
}
op |= dataIn
if er == gpio.FallingEdge {
op |= dataInFall
}
if l != 0 && rbits != l {
return 0, errors.New("d2xx: mismatched buffer lengths")
}
l = rbits
}
b := [3]byte{op, byte(l - 1)}
cmd := b[:2]
if wbits != 0 {
cmd = append(cmd, w)
}
if rbits != 0 {
cmd = append(cmd, flush)
}
if _, err := h.Write(cmd); err != nil {
return 0, err
}
if rbits != 0 {
ctx, cancel := context200ms()
defer cancel()
_, err := h.ReadAll(ctx, b[:1])
return b[0], err
}
return 0, nil
}
// MPSSECBus operates on 8 GPIOs at a time C0~C7.
//
// Direction 1 means output, 0 means input.
func (h *handle) MPSSECBus(mask, value byte) error {
b := [...]byte{gpioSetC, value, mask}
_, err := h.Write(b[:])
return err
}
// MPSSEDBus operates on 8 GPIOs at a time D0~D7.
//
// Direction 1 means output, 0 means input.
func (h *handle) MPSSEDBus(mask, value byte) error {
b := [...]byte{gpioSetD, value, mask}
_, err := h.Write(b[:])
return err
}
// MPSSECBusRead reads all the CBus pins C0~C7.
func (h *handle) MPSSECBusRead() (byte, error) {
b := [...]byte{gpioReadC, flush}
if _, err := h.Write(b[:]); err != nil {
return 0, err
}
ctx, cancel := context200ms()
defer cancel()
if _, err := h.ReadAll(ctx, b[:1]); err != nil {
return 0, err
}
return b[0], nil
}
// MPSSEDBusRead reads all the DBus pins D0~D7.
func (h *handle) MPSSEDBusRead() (byte, error) {
b := [...]byte{gpioReadD, flush}
if _, err := h.Write(b[:]); err != nil {
return 0, err
}
ctx, cancel := context200ms()
defer cancel()
if _, err := h.ReadAll(ctx, b[:1]); err != nil {
return 0, err
}
return b[0], nil
}
func context200ms() (context.Context, func()) {
return context.WithTimeout(context.Background(), 200*time.Millisecond)
}

205
vendor/periph.io/x/host/v3/ftdi/mpsse_gpio.go generated vendored Normal file
View File

@ -0,0 +1,205 @@
// 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 ftdi
import (
"errors"
"fmt"
"strconv"
"time"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/physic"
)
// gpiosMPSSE is a slice of 8 GPIO pins driven via MPSSE.
//
// This permits keeping a cache.
type gpiosMPSSE struct {
// Immutable.
h *handle
cbus bool // false if D bus
pins [8]gpioMPSSE
// Cache of values
direction byte
value byte
}
func (g *gpiosMPSSE) init(name string) {
s := "D"
if g.cbus {
s = "C"
}
// Configure pulls; pull ups are 75kΩ.
// http://www.ftdichip.com/Support/Documents/AppNotes/AN_184%20FTDI%20Device%20Input%20Output%20Pin%20States.pdf
// has a good table.
// D0, D2 and D4 go in high impedance before going into pull up.
// TODO(maruel): The pull on CBus depends on EEPROM!
for i := range g.pins {
g.pins[i].a = g
g.pins[i].n = name + "." + s + strconv.Itoa(i)
g.pins[i].num = i
g.pins[i].dp = gpio.PullUp
}
if g.cbus {
// That's just the default EEPROM value.
g.pins[7].dp = gpio.PullDown
}
}
func (g *gpiosMPSSE) in(n int) error {
if g.h == nil {
return errors.New("d2xx: device not open")
}
g.direction = g.direction & ^(1 << uint(n))
if g.cbus {
return g.h.MPSSECBus(g.direction, g.value)
}
return g.h.MPSSEDBus(g.direction, g.value)
}
func (g *gpiosMPSSE) read() (byte, error) {
if g.h == nil {
return 0, errors.New("d2xx: device not open")
}
var err error
if g.cbus {
g.value, err = g.h.MPSSECBusRead()
} else {
g.value, err = g.h.MPSSEDBusRead()
}
return g.value, err
}
func (g *gpiosMPSSE) out(n int, l gpio.Level) error {
if g.h == nil {
return errors.New("d2xx: device not open")
}
g.direction = g.direction | (1 << uint(n))
if l {
g.value |= 1 << uint(n)
} else {
g.value &^= 1 << uint(n)
}
if g.cbus {
return g.h.MPSSECBus(g.direction, g.value)
}
return g.h.MPSSEDBus(g.direction, g.value)
}
//
// gpioMPSSE is a GPIO pin on a FTDI device driven via MPSSE.
//
// gpioMPSSE implements gpio.PinIO.
//
// It is immutable and stateless.
type gpioMPSSE struct {
a *gpiosMPSSE
n string
num int
dp gpio.Pull
}
// String implements pin.Pin.
func (g *gpioMPSSE) String() string {
return g.n
}
// Name implements pin.Pin.
func (g *gpioMPSSE) Name() string {
return g.n
}
// Number implements pin.Pin.
func (g *gpioMPSSE) Number() int {
return g.num
}
// Function implements pin.Pin.
func (g *gpioMPSSE) Function() string {
s := "Out/"
m := byte(1 << uint(g.num))
if g.a.direction&m == 0 {
s = "In/"
_, _ = g.a.read()
}
return s + gpio.Level(g.a.value&m != 0).String()
}
// Halt implements gpio.PinIO.
func (g *gpioMPSSE) Halt() error {
return nil
}
// In implements gpio.PinIn.
func (g *gpioMPSSE) In(pull gpio.Pull, e gpio.Edge) error {
if e != gpio.NoEdge {
// We could support it on D5.
return errors.New("d2xx: edge triggering is not supported")
}
if pull != g.dp && pull != gpio.PullNoChange {
// TODO(maruel): This needs to be redone:
// - EEPROM values FT232hCBusTristatePullUp and FT232hCBusPwrEnable can be
// used to control individual CBus pins.
// - dataTristate enables gpio.Float when set to output High, but I don't
// know if it will enable reading the value (?). This needs to be
// confirmed.
return fmt.Errorf("d2xx: pull %s is not supported; try %s", pull, g.dp)
}
return g.a.in(g.num)
}
// Read implements gpio.PinIn.
func (g *gpioMPSSE) Read() gpio.Level {
v, _ := g.a.read()
return gpio.Level(v&(1<<uint(g.num)) != 0)
}
// WaitForEdge implements gpio.PinIn.
func (g *gpioMPSSE) WaitForEdge(t time.Duration) bool {
return false
}
// DefaultPull implements gpio.PinIn.
func (g *gpioMPSSE) DefaultPull() gpio.Pull {
return g.dp
}
// Pull implements gpio.PinIn. The resistor is 75kΩ.
func (g *gpioMPSSE) Pull() gpio.Pull {
// See In() for the challenges.
return g.dp
}
// Out implements gpio.PinOut.
func (g *gpioMPSSE) Out(l gpio.Level) error {
return g.a.out(g.num, l)
}
// PWM implements gpio.PinOut.
func (g *gpioMPSSE) PWM(d gpio.Duty, f physic.Frequency) error {
return errors.New("d2xx: not implemented")
}
/*
func (g *gpioMPSSE) Drive() physic.ElectricCurrent {
//return g.a.ee.CDriveCurrent * physic.MilliAmpere
return 2 * physic.MilliAmpere
}
func (g *gpioMPSSE) SlewLimit() bool {
//return g.a.ee.CSlowSlew
return false
}
func (g *gpioMPSSE) Hysteresis() bool {
//return g.a.ee.DSchmittInput
return true
}
*/
var _ gpio.PinIO = &gpioMPSSE{}

85
vendor/periph.io/x/host/v3/ftdi/pin.go generated vendored Normal file
View File

@ -0,0 +1,85 @@
// 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.
// Emulate independent GPIOs.
package ftdi
import (
"errors"
"time"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/physic"
)
// invalidPin is a non-working (not implemented) pin on a FTDI device.
//
// invalidPin implements gpio.PinIO.
type invalidPin struct {
n string
num int
}
// String implements pin.Pin.
func (p *invalidPin) String() string {
return p.n
}
// Name implements pin.Pin.
func (p *invalidPin) Name() string {
return p.n
}
// Number implements pin.Pin.
func (p *invalidPin) Number() int {
return p.num
}
// Function implements pin.Pin.
func (p *invalidPin) Function() string {
return "N/A"
}
// Halt implements gpio.PinIO.
func (p *invalidPin) Halt() error {
return nil
}
// In implements gpio.PinIn.
func (p *invalidPin) In(pull gpio.Pull, e gpio.Edge) error {
return errors.New("d2xx: to be implemented")
}
// Read implements gpio.PinIn.
func (p *invalidPin) Read() gpio.Level {
return gpio.Low
}
// WaitForEdge implements gpio.PinIn.
func (p *invalidPin) WaitForEdge(t time.Duration) bool {
return false
}
// Pull implements gpio.PinIn.
func (p *invalidPin) Pull() gpio.Pull {
return gpio.PullNoChange
}
// DefaultPull implements gpio.PinIn.
func (p *invalidPin) DefaultPull() gpio.Pull {
return gpio.PullNoChange
}
// Out implements gpio.PinOut.
func (p *invalidPin) Out(l gpio.Level) error {
return errors.New("d2xx: to be implemented")
}
// PWM implements gpio.PinOut.
func (p *invalidPin) PWM(d gpio.Duty, f physic.Frequency) error {
return errors.New("d2xx: to be implemented")
}
var _ gpio.PinIO = &invalidPin{}

697
vendor/periph.io/x/host/v3/ftdi/spi.go generated vendored Normal file
View File

@ -0,0 +1,697 @@
// 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.
// This functionality requires MPSSE.
//
// Interfacing SPI:
// http://www.ftdichip.com/Support/Documents/AppNotes/AN_114_FTDI_Hi_Speed_USB_To_SPI_Example.pdf
//
// Implementation based on
// http://www.ftdichip.com/Support/Documents/AppNotes/AN_180_FT232H%20MPSSE%20Example%20-%20USB%20Current%20Meter%20using%20the%20SPI%20interface.pdf
package ftdi
import (
"context"
"errors"
"fmt"
"periph.io/x/conn/v3"
"periph.io/x/conn/v3/gpio"
"periph.io/x/conn/v3/physic"
"periph.io/x/conn/v3/spi"
)
// spiMPSEEPort is an SPI port over a FTDI device in MPSSE mode using the data
// command on the AD bus.
type spiMPSEEPort struct {
c spiMPSEEConn
// Mutable.
maxFreq physic.Frequency
}
func (s *spiMPSEEPort) Close() error {
s.c.f.mu.Lock()
s.c.f.usingSPI = false
s.maxFreq = 0
s.c.edgeInvert = false
s.c.clkActiveLow = false
s.c.noCS = false
s.c.lsbFirst = false
s.c.halfDuplex = false
s.c.f.mu.Unlock()
return nil
}
func (s *spiMPSEEPort) String() string {
return s.c.f.String()
}
// Connect implements spi.Port.
func (s *spiMPSEEPort) Connect(f physic.Frequency, m spi.Mode, bits int) (spi.Conn, error) {
if f > physic.GigaHertz {
return nil, fmt.Errorf("d2xx: invalid speed %s; maximum supported clock is 30MHz", f)
}
if f > 30*physic.MegaHertz {
// TODO(maruel): Figure out a way to communicate that the speed was lowered.
// https://github.com/google/periph/issues/255
f = 30 * physic.MegaHertz
}
if f < 100*physic.Hertz {
return nil, fmt.Errorf("d2xx: invalid speed %s; minimum supported clock is 100Hz; did you forget to multiply by physic.MegaHertz?", f)
}
if bits&7 != 0 {
return nil, errors.New("d2xx: bits must be multiple of 8")
}
if bits != 8 {
return nil, errors.New("d2xx: implement bits per word above 8")
}
s.c.f.mu.Lock()
defer s.c.f.mu.Unlock()
s.c.noCS = m&spi.NoCS != 0
s.c.halfDuplex = m&spi.HalfDuplex != 0
s.c.lsbFirst = m&spi.LSBFirst != 0
m &^= spi.NoCS | spi.HalfDuplex | spi.LSBFirst
if s.c.halfDuplex {
return nil, errors.New("d2xx: spi.HalfDuplex is not yet supported (implementing wouldn't be too hard, please submit a PR")
}
if m < 0 || m > 3 {
return nil, errors.New("d2xx: unknown spi mode")
}
s.c.edgeInvert = m&1 != 0
s.c.clkActiveLow = m&2 != 0
if s.maxFreq == 0 || f < s.maxFreq {
// TODO(maruel): We could set these only *during* the SPI operation, which
// would make more sense.
if _, err := s.c.f.h.MPSSEClock(f); err != nil {
return nil, err
}
s.maxFreq = f
}
s.c.resetIdle()
if err := s.c.f.h.MPSSEDBus(s.c.f.dbus.direction, s.c.f.dbus.value); err != nil {
return nil, err
}
s.c.f.usingSPI = true
return &s.c, nil
}
// LimitSpeed implements spi.Port.
func (s *spiMPSEEPort) LimitSpeed(f physic.Frequency) error {
if f > physic.GigaHertz {
return fmt.Errorf("d2xx: invalid speed %s; maximum supported clock is 30MHz", f)
}
if f > 30*physic.MegaHertz {
f = 30 * physic.MegaHertz
}
if f < 100*physic.Hertz {
return errors.New("d2xx: minimum supported clock is 100Hz; did you forget to multiply by physic.MegaHertz?")
}
s.c.f.mu.Lock()
defer s.c.f.mu.Unlock()
if s.maxFreq != 0 && s.maxFreq <= f {
return nil
}
s.maxFreq = f
// TODO(maruel): We could set these only *during* the SPI operation, which
// would make more sense.
_, err := s.c.f.h.MPSSEClock(s.maxFreq)
return err
}
// CLK returns the SCK (clock) pin.
func (s *spiMPSEEPort) CLK() gpio.PinOut {
return s.c.CLK()
}
// MOSI returns the SDO (master out, slave in) pin.
func (s *spiMPSEEPort) MOSI() gpio.PinOut {
return s.c.MOSI()
}
// MISO returns the SDI (master in, slave out) pin.
func (s *spiMPSEEPort) MISO() gpio.PinIn {
return s.c.MISO()
}
// CS returns the CSN (chip select) pin.
func (s *spiMPSEEPort) CS() gpio.PinOut {
return s.c.CS()
}
type spiMPSEEConn struct {
// Immutable.
f *FT232H
// Initialized at Connect().
edgeInvert bool // CPHA=1
clkActiveLow bool // CPOL=1
noCS bool // CS line is not changed
lsbFirst bool // Default is MSB first
halfDuplex bool // 3 wire mode
}
func (s *spiMPSEEConn) String() string {
return s.f.String()
}
func (s *spiMPSEEConn) Tx(w, r []byte) error {
var p = [1]spi.Packet{{W: w, R: r}}
return s.TxPackets(p[:])
}
func (s *spiMPSEEConn) Duplex() conn.Duplex {
// TODO(maruel): Support half if there's a need.
return conn.Full
}
func (s *spiMPSEEConn) TxPackets(pkts []spi.Packet) error {
// Verification.
for _, p := range pkts {
if p.KeepCS {
return errors.New("d2xx: implement spi.Packet.KeepCS")
}
if p.BitsPerWord&7 != 0 {
return errors.New("d2xx: bits must be a multiple of 8")
}
if p.BitsPerWord != 0 && p.BitsPerWord != 8 {
return errors.New("d2xx: implement spi.Packet.BitsPerWord")
}
if err := verifyBuffers(p.W, p.R); err != nil {
return err
}
}
s.f.mu.Lock()
defer s.f.mu.Unlock()
const clk = byte(1) << 0
const mosi = byte(1) << 1
const miso = byte(1) << 2
const cs = byte(1) << 3
s.resetIdle()
idle := s.f.dbus.value
start1 := idle
if !s.noCS {
start1 &^= cs
}
// In mode 0 and 2, start2 is not needed.
start2 := start1
stop := idle
if s.edgeInvert {
// This is needed to 'prime' the clock.
start2 ^= clk
// With mode 1 and 3, keep the clock steady while CS is being deasserted to
// not create a spurious clock.
stop ^= clk
}
ew := gpio.FallingEdge
er := gpio.RisingEdge
if s.edgeInvert {
ew, er = er, ew
}
if s.clkActiveLow {
// TODO(maruel): Not sure.
ew, er = er, ew
}
// FT232H claims 512 USB packet support, so to reduce the chatter over USB,
// try to make all I/O be aligned on this amount. This also removes the need
// for heap usage. The idea is to always trail reads by one buffer. This is
// fine as the device has 1024 byte read buffer. Operations look like this:
// W, W, R, W, R, W, R, R
// This enables reducing the I/O gaps between USB packets as the device is
// always busy with operations.
var buf [512]byte
cmd := buf[:0]
keptCS := false
// Loop, without increasing the index.
for _, p := range pkts {
if len(p.W) == 0 && len(p.R) == 0 {
continue
}
// TODO(maruel): s.halfDuplex.
if !keptCS {
for i := 0; i < 5; i++ {
cmd = append(cmd, gpioSetD, idle, s.f.dbus.direction)
}
for i := 0; i < 5; i++ {
cmd = append(cmd, gpioSetD, start1, s.f.dbus.direction)
}
}
if s.edgeInvert {
// This is needed to 'prime' the clock.
for i := 0; i < 5; i++ {
cmd = append(cmd, gpioSetD, start2, s.f.dbus.direction)
}
}
op := mpsseTxOp(len(p.W) != 0, len(p.R) != 0, ew, er, s.lsbFirst)
// Do an I/O loop. We can mutate p here because it is a copy.
// TODO(maruel): Have the pipeline cross the packet boundary.
if len(p.W) == 0 {
// Have the write buffer point to the read one. This saves from
// allocating memory. The side effect is that it will write whatever
// happened to be in the read buffer.
p.W = p.R[:]
}
pendingRead := 0
for len(p.W) != 0 {
// op, sizelo, sizehi.
chunk := len(buf) - 3 - len(cmd)
if l := len(p.W); chunk > l {
chunk = l
}
cmd = append(cmd, op, byte(chunk-1), byte((chunk-1)>>8))
cmd = append(cmd, p.W[:chunk]...)
p.W = p.W[chunk:]
if _, err := s.f.h.WriteFast(cmd); err != nil {
return err
}
cmd = buf[:0]
// TODO(maruel): Read 62 bytes at a time?
// Delay reading by 512 bytes.
if pendingRead >= 512 {
if len(p.R) != 0 {
// Align reads on 512 bytes exactly, aligned on USB packet size.
if _, err := s.f.h.ReadAll(context.Background(), p.R[:512]); err != nil {
return err
}
p.R = p.R[512:]
pendingRead -= 512
}
}
pendingRead += chunk
}
// Do not forget to read whatever is pending.
// TODO(maruel): Investigate if a flush helps.
if len(p.R) != 0 {
// Send a flush to not wait for data.
cmd = append(cmd, flush)
if _, err := s.f.h.WriteFast(cmd); err != nil {
return err
}
cmd = buf[:0]
if _, err := s.f.h.ReadAll(context.Background(), p.R); err != nil {
return err
}
}
// TODO(maruel): Inject this in the write if it fits (it will generally
// do). That will save one USB I/O, which is not insignificant.
keptCS = p.KeepCS
if !keptCS {
cmd = append(cmd, flush)
for i := 0; i < 5; i++ {
cmd = append(cmd, gpioSetD, stop, s.f.dbus.direction)
}
for i := 0; i < 5; i++ {
cmd = append(cmd, gpioSetD, idle, s.f.dbus.direction)
}
if _, err := s.f.h.WriteFast(cmd); err != nil {
return err
}
cmd = buf[:0]
}
}
return nil
}
// CLK returns the SCK (clock) pin.
func (s *spiMPSEEConn) CLK() gpio.PinOut {
return s.f.D0
}
// MOSI returns the SDO (master out, slave in) pin.
func (s *spiMPSEEConn) MOSI() gpio.PinOut {
return s.f.D1
}
// MISO returns the SDI (master in, slave out) pin.
func (s *spiMPSEEConn) MISO() gpio.PinIn {
return s.f.D2
}
// CS returns the CSN (chip select) pin.
func (s *spiMPSEEConn) CS() gpio.PinOut {
return s.f.D3
}
// resetIdle sets D0~D3. D0, D1 and D3 are output but only touch D3 is CS is
// used.
func (s *spiMPSEEConn) resetIdle() {
const clk = byte(1) << 0
const mosi = byte(1) << 1
const miso = byte(1) << 2
const cs = byte(1) << 3
if !s.noCS {
s.f.dbus.direction &= 0xF0
s.f.dbus.direction |= cs
s.f.dbus.value &= 0xF0
s.f.dbus.value |= cs
} else {
s.f.dbus.value &= 0xF8
s.f.dbus.direction &= 0xF8
}
s.f.dbus.direction |= mosi | clk
if s.clkActiveLow {
// Clock idles high.
s.f.dbus.value |= clk
}
}
//
// spiSyncPort is an SPI port over a FTDI device in synchronous bit-bang mode.
type spiSyncPort struct {
c spiSyncConn
// Mutable.
maxFreq physic.Frequency
}
func (s *spiSyncPort) Close() error {
s.c.f.mu.Lock()
s.c.f.usingSPI = false
s.maxFreq = 0
s.c.edgeInvert = false
s.c.clkActiveLow = false
s.c.noCS = false
s.c.lsbFirst = false
s.c.halfDuplex = false
s.c.f.mu.Unlock()
return nil
}
func (s *spiSyncPort) String() string {
return s.c.f.String()
}
const ft232rMaxSpeed = 3 * physic.MegaHertz
// Connect implements spi.Port.
func (s *spiSyncPort) Connect(f physic.Frequency, m spi.Mode, bits int) (spi.Conn, error) {
if f > physic.GigaHertz {
return nil, fmt.Errorf("d2xx: invalid speed %s; maximum supported clock is 1.5MHz", f)
}
if f > ft232rMaxSpeed/2 {
// TODO(maruel): Figure out a way to communicate that the speed was lowered.
// https://github.com/google/periph/issues/255
f = ft232rMaxSpeed / 2
}
if f < 100*physic.Hertz {
return nil, fmt.Errorf("d2xx: invalid speed %s; minimum supported clock is 100Hz; did you forget to multiply by physic.MegaHertz?", f)
}
if bits&7 != 0 {
return nil, errors.New("d2xx: bits must be multiple of 8")
}
if bits != 8 {
return nil, errors.New("d2xx: implement bits per word above 8")
}
s.c.f.mu.Lock()
defer s.c.f.mu.Unlock()
s.c.noCS = m&spi.NoCS != 0
s.c.halfDuplex = m&spi.HalfDuplex != 0
s.c.lsbFirst = m&spi.LSBFirst != 0
m &^= spi.NoCS | spi.HalfDuplex | spi.LSBFirst
if s.c.halfDuplex {
return nil, errors.New("d2xx: spi.HalfDuplex is not yet supported (implementing wouldn't be too hard, please submit a PR")
}
if m < 0 || m > 3 {
return nil, errors.New("d2xx: unknown spi mode")
}
s.c.edgeInvert = m&1 != 0
s.c.clkActiveLow = m&2 != 0
if s.maxFreq == 0 || f < s.maxFreq {
if err := s.c.f.SetSpeed(f * 2); err != nil {
return nil, err
}
s.maxFreq = f
}
// D0, D2 and D3 are output. D4~D7 are kept as-is.
const mosi = byte(1) << 0 // TX
const miso = byte(1) << 1 // RX
const clk = byte(1) << 2 // RTS
const cs = byte(1) << 3 // CTS
mask := mosi | clk | cs | (s.c.f.dmask & 0xF0)
if err := s.c.f.setDBusMaskLocked(mask); err != nil {
return nil, err
}
// TODO(maruel): Combine both following calls if possible. We'd shave off a
// few ms.
if !s.c.noCS {
// CTS/SPI_CS is active low.
if err := s.c.f.dbusSyncGPIOOutLocked(3, gpio.High); err != nil {
return nil, err
}
}
if s.c.clkActiveLow {
// RTS/SPI_CLK is active low.
if err := s.c.f.dbusSyncGPIOOutLocked(2, gpio.High); err != nil {
return nil, err
}
}
s.c.f.usingSPI = true
return &s.c, nil
}
// LimitSpeed implements spi.Port.
func (s *spiSyncPort) LimitSpeed(f physic.Frequency) error {
if f > physic.GigaHertz {
return fmt.Errorf("d2xx: invalid speed %s; maximum supported clock is 1.5MHz", f)
}
if f < 100*physic.Hertz {
return fmt.Errorf("d2xx: invalid speed %s; minimum supported clock is 100Hz; did you forget to multiply by physic.MegaHertz?", f)
}
s.c.f.mu.Lock()
defer s.c.f.mu.Unlock()
if s.maxFreq != 0 && s.maxFreq <= f {
return nil
}
if err := s.c.f.SetSpeed(f * 2); err == nil {
s.maxFreq = f
}
return nil
}
// CLK returns the SCK (clock) pin.
func (s *spiSyncPort) CLK() gpio.PinOut {
return s.c.CLK()
}
// MOSI returns the SDO (master out, slave in) pin.
func (s *spiSyncPort) MOSI() gpio.PinOut {
return s.c.MOSI()
}
// MISO returns the SDI (master in, slave out) pin.
func (s *spiSyncPort) MISO() gpio.PinIn {
return s.c.MISO()
}
// CS returns the CSN (chip select) pin.
func (s *spiSyncPort) CS() gpio.PinOut {
return s.c.CS()
}
type spiSyncConn struct {
// Immutable.
f *FT232R
// Initialized at Connect().
edgeInvert bool // CPHA=1
clkActiveLow bool // CPOL=1
noCS bool // CS line is not changed
lsbFirst bool // Default is MSB first
halfDuplex bool // 3 wire mode
}
func (s *spiSyncConn) String() string {
return s.f.String()
}
func (s *spiSyncConn) Tx(w, r []byte) error {
var p = [1]spi.Packet{{W: w, R: r}}
return s.TxPackets(p[:])
}
func (s *spiSyncConn) Duplex() conn.Duplex {
// TODO(maruel): Support half if there's a need.
return conn.Full
}
func (s *spiSyncConn) TxPackets(pkts []spi.Packet) error {
// We need to 'expand' each bit 2 times * 8 bits, which leads
// to a 16x memory usage increase. Adds 5 samples before and after.
totalW := 0
totalR := 0
for _, p := range pkts {
if p.KeepCS {
return errors.New("d2xx: implement spi.Packet.KeepCS")
}
if p.BitsPerWord&7 != 0 {
return errors.New("d2xx: bits must be a multiple of 8")
}
if p.BitsPerWord != 0 && p.BitsPerWord != 8 {
return errors.New("d2xx: implement spi.Packet.BitsPerWord")
}
if err := verifyBuffers(p.W, p.R); err != nil {
return err
}
// TODO(maruel): Correctly calculate offsets.
if len(p.W) != 0 {
totalW += 2 * 8 * len(p.W)
}
if len(p.R) != 0 {
totalR += 2 * 8 * len(p.R)
}
}
// Create a large, single chunk.
var we, re []byte
if totalW != 0 {
totalW += 10
we = make([]byte, 0, totalW)
}
if totalR != 0 {
totalR += 10
re = make([]byte, totalR)
}
const mosi = byte(1) << 0 // TX
const miso = byte(1) << 1 // RX
const clk = byte(1) << 2 // RTS
const cs = byte(1) << 3 // CTS
s.f.mu.Lock()
defer s.f.mu.Unlock()
// https://en.wikipedia.org/wiki/Serial_Peripheral_Interface#Data_transmission
csActive := s.f.dvalue & s.f.dmask & 0xF0
csIdle := csActive
if !s.noCS {
csIdle = csActive | cs
}
clkIdle := csActive
clkActive := clkIdle | clk
if s.clkActiveLow {
clkActive, clkIdle = clkIdle, clkActive
csIdle |= clk
}
// Start of tx; assert CS if needed.
we = append(we, csIdle, clkIdle, clkIdle, clkIdle, clkIdle)
for _, p := range pkts {
if len(p.W) == 0 && len(p.R) == 0 {
continue
}
// TODO(maruel): s.halfDuplex.
for _, b := range p.W {
for j := uint(0); j < 8; j++ {
// For each bit, handle clock phase and data phase.
bit := byte(0)
if !s.lsbFirst {
// MSBF
if b&(0x80>>j) != 0 {
bit = mosi
}
} else {
// LSBF
if b&(1<<j) != 0 {
bit = mosi
}
}
if !s.edgeInvert {
// Mode0/2; CPHA=0
we = append(we, clkIdle|bit, clkActive|bit)
} else {
// Mode1/3; CPHA=1
we = append(we, clkActive|bit, clkIdle|bit)
}
}
}
}
// End of tx; deassert CS.
we = append(we, clkIdle, clkIdle, clkIdle, clkIdle, csIdle)
if err := s.f.txLocked(we, re); err != nil {
return err
}
// Extract data from re into r.
for _, p := range pkts {
// TODO(maruel): Correctly calculate offsets.
if len(p.W) == 0 && len(p.R) == 0 {
continue
}
// TODO(maruel): halfDuplex.
for i := range p.R {
// For each bit, read at the right data phase.
b := byte(0)
for j := 0; j < 8; j++ {
if re[5+i*8*2+j*2+1]&byte(1)<<1 != 0 {
if !s.lsbFirst {
// MSBF
b |= 0x80 >> uint(j)
} else {
// LSBF
b |= 1 << uint(j)
}
}
}
p.R[i] = b
}
}
return nil
}
// CLK returns the SCK (clock) pin.
func (s *spiSyncConn) CLK() gpio.PinOut {
return s.f.D2 // RTS
}
// MOSI returns the SDO (master out, slave in) pin.
func (s *spiSyncConn) MOSI() gpio.PinOut {
return s.f.D0 // TX
}
// MISO returns the SDI (master in, slave out) pin.
func (s *spiSyncConn) MISO() gpio.PinIn {
return s.f.D1 // RX
}
// CS returns the CSN (chip select) pin.
func (s *spiSyncConn) CS() gpio.PinOut {
return s.f.D3 // CTS
}
//
func verifyBuffers(w, r []byte) error {
if len(w) != 0 {
if len(r) != 0 {
if len(w) != len(r) {
return errors.New("d2xx: both buffers must have the same size")
}
}
// TODO(maruel): When the buffer is >64Kb, cut it in parts and do not
// request a flush. Still try to read though.
if len(w) > 65536 {
return errors.New("d2xx: maximum buffer size is 64Kb")
}
} else if len(r) != 0 {
// TODO(maruel): Remove, this is not a problem.
if len(r) > 65536 {
return errors.New("d2xx: maximum buffer size is 64Kb")
}
}
return nil
}
var _ spi.PortCloser = &spiMPSEEPort{}
var _ spi.Conn = &spiMPSEEConn{}
var _ spi.PortCloser = &spiSyncPort{}
var _ spi.Conn = &spiSyncConn{}

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

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

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

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

13
vendor/periph.io/x/host/v3/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/host/v3/allwinner"
_ "periph.io/x/host/v3/bcm283x"
_ "periph.io/x/host/v3/pine64"
_ "periph.io/x/host/v3/rpi"
)

10
vendor/periph.io/x/host/v3/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/host/v3/sysfs"
)

26
vendor/periph.io/x/host/v3/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/host/v3/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/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/distro"
"periph.io/x/host/v3/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("board Hardkernel ODROID-C0/C1/C1+ 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 {
driverreg.MustRegister(&drv)
}
}
var drv driver

7
vendor/periph.io/x/host/v3/odroidc1/odroidc1_arm.go generated vendored Normal file
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/host/v3/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

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

@ -0,0 +1,271 @@
// 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"
"strings"
"periph.io/x/conn/v3/driver/driverreg"
"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"
)
// Present returns true if running on a Pine64 board.
//
// https://www.pine64.org/
func Present() bool {
if isArm {
return strings.HasPrefix(distro.DTModel(), "Pine64")
}
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 {
driverreg.MustRegister(&drv)
}
}
var drv driver

7
vendor/periph.io/x/host/v3/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

9
vendor/periph.io/x/host/v3/pine64/pine64_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 pine64
const isArm = true

9
vendor/periph.io/x/host/v3/pine64/pine64_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 pine64
const isArm = false

182
vendor/periph.io/x/host/v3/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 {
h := (*reflect.SliceHeader)(unsafe.Pointer(&b))
return h.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/host/v3/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/host/v3/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/host/v3/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/host/v3/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/host/v3/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
}

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

@ -0,0 +1,285 @@
// 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/host/v3/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 {
// It's important to make a copy here.
h := new(reflect.SliceHeader)
h.Data = (*reflect.SliceHeader)(unsafe.Pointer(s)).Data
h.Len = (*reflect.SliceHeader)(unsafe.Pointer(s)).Len / 4
h.Cap = (*reflect.SliceHeader)(unsafe.Pointer(s)).Cap / 4
return *(*[]uint32)(unsafe.Pointer(h))
}
// 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, err2 := mmap(f.Fd(), 0, pageSize); err2 == nil {
gpioMemView = &View{Slice: i, orig: i, phys: 0}
} else {
gpioMemErr = wrapf("failed to memory map in user space GPIO memory: %w", err2)
}
} else {
gpioMemErr = wrapf("failed to open GPIO memory: %w", 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: %w", 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...)
}

Some files were not shown because too many files have changed in this diff Show More