forked from google/periph
/
chip.go
358 lines (336 loc) · 10.7 KB
/
chip.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
// Copyright 2016 The Periph Authors. All rights reserved.
// Use of this source code is governed under the Apache License, Version 2.0
// that can be found in the LICENSE file.
package chip
import (
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"strings"
"periph.io/x/periph"
"periph.io/x/periph/conn/gpio"
"periph.io/x/periph/conn/gpio/gpioreg"
"periph.io/x/periph/conn/pin"
"periph.io/x/periph/conn/pin/pinreg"
"periph.io/x/periph/host/allwinner"
"periph.io/x/periph/host/distro"
"periph.io/x/periph/host/fs"
)
// C.H.I.P. hardware pins.
var (
TEMP_SENSOR = &pin.BasicPin{N: "TEMP_SENSOR"}
PWR_SWITCH = &pin.BasicPin{N: "PWR_SWITCH"}
// XIO "gpio" pins attached to the pcf8574 I²C port extender.
XIO0, XIO1, XIO2, XIO3, XIO4, XIO5, XIO6, XIO7 gpio.PinIO
)
// The U13 header is opposite the power LED.
//
// The alternate pin functionality is described at pages 322-323 of
// https://github.com/NextThingCo/CHIP-Hardware/raw/master/CHIP%5Bv1_0%5D/CHIPv1_0-BOM-Datasheets/Allwinner%20R8%20User%20Manual%20V1.1.pdf
var (
U13_1 = pin.GROUND //
U13_2 = pin.DC_IN //
U13_3 = pin.V5 // (filtered)
U13_4 = pin.GROUND //
U13_5 = pin.V3_3 //
U13_6 = TEMP_SENSOR // Analog temp sensor input
U13_7 = pin.V1_8 //
U13_8 = pin.BAT_PLUS // External LiPo battery
U13_9 = allwinner.PB16 // I2C1_SDA
U13_10 = PWR_SWITCH // Power button
U13_11 = allwinner.PB15 // I2C1_SCL
U13_12 = pin.GROUND //
U13_13 = allwinner.X1 // Touch screen X1
U13_14 = allwinner.X2 // Touch screen X2
U13_15 = allwinner.Y1 // Touch screen Y1
U13_16 = allwinner.Y2 // Touch screen Y2
U13_17 = allwinner.PD2 // LCD-D2; UART2_TX firmware probe for 1-wire to detect DIP at boot; http://docs.getchip.com/dip.html#dip-identification
U13_18 = allwinner.PB2 // PWM0; EINT16
U13_19 = allwinner.PD4 // LCD-D4; UART2_CTS
U13_20 = allwinner.PD3 // LCD-D3; UART2_RX
U13_21 = allwinner.PD6 // LCD-D6
U13_22 = allwinner.PD5 // LCD-D5
U13_23 = allwinner.PD10 // LCD-D10
U13_24 = allwinner.PD7 // LCD-D7
U13_25 = allwinner.PD12 // LCD-D12
U13_26 = allwinner.PD11 // LCD-D11
U13_27 = allwinner.PD14 // LCD-D14
U13_28 = allwinner.PD13 // LCD-D13
U13_29 = allwinner.PD18 // LCD-D18
U13_30 = allwinner.PD15 // LCD-D15
U13_31 = allwinner.PD20 // LCD-D20
U13_32 = allwinner.PD19 // LCD-D19
U13_33 = allwinner.PD22 // LCD-D22
U13_34 = allwinner.PD21 // LCD-D21
U13_35 = allwinner.PD24 // LCD-CLK
U13_36 = allwinner.PD23 // LCD-D23
U13_37 = allwinner.PD26 // LCD-VSYNC
U13_38 = allwinner.PD27 // LCD-HSYNC
U13_39 = pin.GROUND //
U13_40 = allwinner.PD25 // LCD-DE: RGB666 data
)
// The U14 header is right next to the power LED.
var (
U14_1 = pin.GROUND //
U14_2 = pin.V5 // (filtered)
U14_3 = allwinner.PG3 // UART1_TX; EINT3
U14_4 = allwinner.HP_LEFT // Headphone left output
U14_5 = allwinner.PG4 // UART1_RX; EINT4
U14_6 = allwinner.HP_COM // Headphone amp out
U14_7 = allwinner.FEL // Boot mode selection
U14_8 = allwinner.HP_RIGHT // Headphone right output
U14_9 = pin.V3_3 //
U14_10 = allwinner.MIC_GND // Microphone ground
U14_11 = allwinner.KEY_ADC // LRADC Low res analog to digital
U14_12 = allwinner.MIC_IN // Microphone input
U14_13 = XIO0 // gpio via I²C controller
U14_14 = XIO1 // gpio via I²C controller
U14_15 = XIO2 // gpio via I²C controller
U14_16 = XIO3 // gpio via I²C controller
U14_17 = XIO4 // gpio via I²C controller
U14_18 = XIO5 // gpio via I²C controller
U14_19 = XIO6 // gpio via I²C controller
U14_20 = XIO7 // gpio via I²C controller
U14_21 = pin.GROUND //
U14_22 = pin.GROUND //
U14_23 = allwinner.PG1 // GPS_CLK; AP-EINT1
U14_24 = allwinner.PB3 // IR_TX; AP-EINT3 (EINT17)
U14_25 = allwinner.PB18 // I2C2_SDA
U14_26 = allwinner.PB17 // I2C2_SCL
U14_27 = allwinner.PE0 // CSIPCK: CMOS serial interface; SPI2_CS0; EINT14
U14_28 = allwinner.PE1 // CSICK: CMOS serial interface; SPI2_CLK; EINT15
U14_29 = allwinner.PE2 // CSIHSYNC; SPI2_MOSI
U14_30 = allwinner.PE3 // CSIVSYNC; SPI2_MISO
U14_31 = allwinner.PE4 // CSID0
U14_32 = allwinner.PE5 // CSID1
U14_33 = allwinner.PE6 // CSID2
U14_34 = allwinner.PE7 // CSID3
U14_35 = allwinner.PE8 // CSID4
U14_36 = allwinner.PE9 // CSID5
U14_37 = allwinner.PE10 // CSID6; UART1_RX
U14_38 = allwinner.PE11 // CSID7; UART1_TX
U14_39 = pin.GROUND //
U14_40 = pin.GROUND //
)
// Present returns true if running on a NextThing Co's C.H.I.P. board.
//
// It looks for "C.H.I.P" in the device tree. The following information is
// expected in the device dtree:
// root@chip2:/proc/device-tree# od -c compatible
// 0000000 n e x t t h i n g , c h i p \0 a
// 0000020 l l w i n n e r , s u n 5 i - r
// 0000040 8 \0
// root@chip2:/proc/device-tree# od -c model
// 0000000 N e x t T h i n g C . H . I .
// 0000020 P . \0
func Present() bool {
return strings.Contains(distro.DTModel(), "C.H.I.P")
}
//
// aliases is a list of aliases for the various gpio pins, this allows users to
// refer to pins using the documented and labeled names instead of some GPIOnnn
// name. The map key is the alias and the value is the real pin name.
var aliases = map[string]string{
"AP-EINT1": "PG1",
"AP-EINT3": "PB3",
"CSIPCK": "PE0",
"CSIHSYNC": "PE2",
"CSID0": "PE4",
"CSID2": "PE6",
"CSID4": "PE8",
"CSID6": "PE10",
"CSICK": "PE1",
"CSIVSYNC": "PE3",
"CSID1": "PE5",
"CSID3": "PE7",
"CSID5": "PE9",
"CSID7": "PE11",
"LCD-CLK": "PD24",
"LCD-D10": "PD10",
"LCD-D11": "PD11",
"LCD-D12": "PD12",
"LCD-D13": "PD13",
"LCD-D14": "PD14",
"LCD-D15": "PD15",
"LCD-D18": "PD18",
"LCD-D19": "PD19",
"LCD-D2": "PD2",
"LCD-D20": "PD20",
"LCD-D21": "PD21",
"LCD-D22": "PD22",
"LCD-D23": "PD23",
"LCD-D3": "PD3",
"LCD-D4": "PD4",
"LCD-D5": "PD5",
"LCD-D6": "PD6",
"LCD-D7": "PD7",
"LCD-DE": "PD25",
"LCD-HSYNC": "PD27",
"LCD-VSYNC": "PD26",
"TWI1-SCK": "PB15",
"TWI1-SDA": "PB16",
"TWI2-SCK": "PB17",
"TWI2-SDA": "PB18",
"UART1-RX": "PG4",
"UART1-TX": "PG3",
}
func init() {
// These are initialized later by the driver.
XIO0 = gpio.INVALID
XIO1 = gpio.INVALID
XIO2 = gpio.INVALID
XIO3 = gpio.INVALID
XIO4 = gpio.INVALID
XIO5 = gpio.INVALID
XIO6 = gpio.INVALID
XIO7 = gpio.INVALID
// These must be reinitialized.
U14_13 = XIO0
U14_14 = XIO1
U14_15 = XIO2
U14_16 = XIO3
U14_17 = XIO4
U14_18 = XIO5
U14_19 = XIO6
U14_20 = XIO7
}
// findXIOBase calculates the base of the XIO-P? gpio pins as explained in
// http://docs.getchip.com/chip.html#kernel-4-3-vs-4-4-gpio-how-to-tell-the-difference
//
// The XIO-P? sysfs mapped pin number changed in kernel 4.3, 4.4.11 and again
// in 4.4.13 so it is better to query sysfs.
func findXIOBase() int {
chips, err := filepath.Glob("/sys/class/gpio/gpiochip*/label")
if err != nil {
return -1
}
for _, item := range chips {
f, err := fs.Open(item, os.O_RDONLY)
if err != nil {
continue
}
b, err := ioutil.ReadAll(f)
if err1 := f.Close(); err == nil {
err = err1
}
if err != nil {
continue
}
if string(b) == "pcf8574a\n" {
id, err := strconv.Atoi(filepath.Base(filepath.Dir(item))[8:])
if err != nil {
return -1
}
return id
}
}
return -1
}
// driver implements drivers.Driver.
type driver struct {
}
func (d *driver) String() string {
return "chip"
}
func (d *driver) Prerequisites() []string {
return nil
}
func (d *driver) After() []string {
// has allwinner cpu, needs sysfs for XIO0-XIO7 "gpio" pins
return []string{"allwinner-gpio", "sysfs-gpio"}
}
func (d *driver) Init() (bool, error) {
if !Present() {
return false, errors.New("NextThing Co. CHIP board not detected")
}
base := findXIOBase()
if base == -1 {
return true, errors.New("couldn't find XIO pins base number")
}
for i := 0; i < 8; i++ {
aliases[fmt.Sprintf("XIO-P%d", i)] = fmt.Sprintf("GPIO%d", base+i)
}
// At this point the sysfs driver has initialized and discovered its pins,
// we can now hook-up the appropriate CHIP pins to sysfs gpio pins.
for alias, real := range aliases {
if err := gpioreg.RegisterAlias(alias, real); err != nil {
return true, err
}
}
// These must be explicitly initialized.
XIO0 = gpioreg.ByName("XIO-P0")
XIO1 = gpioreg.ByName("XIO-P1")
XIO2 = gpioreg.ByName("XIO-P2")
XIO3 = gpioreg.ByName("XIO-P3")
XIO4 = gpioreg.ByName("XIO-P4")
XIO5 = gpioreg.ByName("XIO-P5")
XIO6 = gpioreg.ByName("XIO-P6")
XIO7 = gpioreg.ByName("XIO-P7")
U14_13 = XIO0
U14_14 = XIO1
U14_15 = XIO2
U14_16 = XIO3
U14_17 = XIO4
U14_18 = XIO5
U14_19 = XIO6
U14_20 = XIO7
// U13 is one of the 20x2 connectors.
U13 := [][]pin.Pin{
{U13_1, U13_2},
{U13_3, U13_4},
{U13_5, U13_6},
{U13_7, U13_8},
{gpioreg.ByName("TWI1-SDA"), U13_10},
{gpioreg.ByName("TWI1-SCK"), U13_12},
{U13_13, U13_14},
{U13_15, U13_16},
{gpioreg.ByName("LCD-D2"), gpioreg.ByName("PWM0")},
{gpioreg.ByName("LCD-D4"), gpioreg.ByName("LCD-D3")},
{gpioreg.ByName("LCD-D6"), gpioreg.ByName("LCD-D5")},
{gpioreg.ByName("LCD-D10"), gpioreg.ByName("LCD-D7")},
{gpioreg.ByName("LCD-D12"), gpioreg.ByName("LCD-D11")},
{gpioreg.ByName("LCD-D14"), gpioreg.ByName("LCD-D13")},
{gpioreg.ByName("LCD-D18"), gpioreg.ByName("LCD-D15")},
{gpioreg.ByName("LCD-D20"), gpioreg.ByName("LCD-D19")},
{gpioreg.ByName("LCD-D22"), gpioreg.ByName("LCD-D21")},
{gpioreg.ByName("LCD-CLK"), gpioreg.ByName("LCD-D23")},
{gpioreg.ByName("LCD-VSYNC"), gpioreg.ByName("LCD-HSYNC")},
{U13_39, gpioreg.ByName("LCD-DE")},
}
if err := pinreg.Register("U13", U13); err != nil {
return true, err
}
// U14 is one of the 20x2 connectors.
U14 := [][]pin.Pin{
{U14_1, U14_2},
{gpioreg.ByName("UART1-TX"), U14_4},
{gpioreg.ByName("UART1-RX"), U14_6},
{U14_7, U14_8},
{U14_9, U14_10},
{U14_11, U14_12}, // TODO(maruel): switch to LRADC once analog support is added
{U14_13, U14_14},
{U14_15, U14_16},
{U14_17, U14_18},
{U14_19, U14_20},
{U14_21, U14_22},
{gpioreg.ByName("AP-EINT1"), gpioreg.ByName("AP-EINT3")},
{gpioreg.ByName("TWI2-SDA"), gpioreg.ByName("TWI2-SCK")},
{gpioreg.ByName("CSIPCK"), gpioreg.ByName("CSICK")},
{gpioreg.ByName("CSIHSYNC"), gpioreg.ByName("CSIVSYNC")},
{gpioreg.ByName("CSID0"), gpioreg.ByName("CSID1")},
{gpioreg.ByName("CSID2"), gpioreg.ByName("CSID3")},
{gpioreg.ByName("CSID4"), gpioreg.ByName("CSID5")},
{gpioreg.ByName("CSID6"), gpioreg.ByName("CSID7")},
{U14_39, U14_40},
}
return true, pinreg.Register("U14", U14)
}
func init() {
if isArm {
periph.MustRegister(&drv)
}
}
var drv driver