blob: f2db0b22933398de7efa480b9f19a817649530a7 [file] [edit]
// Copyright 2026 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package zephyr_dtsi
import (
"os"
"path/filepath"
"testing"
)
func getChipOrFatal(t *testing.T, name string) *Chip {
c, ok := GetChip(name)
if !ok {
t.Fatalf("Chip %s not found", name)
}
return c
}
func TestNPCX99_ResolveGPIO(t *testing.T) {
chip := getChipOrFatal(t, "npcx99")
tests := []struct {
pinNum string
expectedPort string
expectedPin int
expectErr bool
}{
{"A2", "3", 1, false}, // KSI0/GPIO31/TRACEDATA3/GP_MOSI
{"B10", "0", 6, false}, // KSO11/GPIO06
{"D10", "c", 6, false}, // GPIOC6/SMI#
{"D1", "", 0, true}, // AVCC (not a GPIO)
{"Z99", "", 0, true}, // Pin not found
}
for _, tt := range tests {
port, pin, err := chip.ResolveGPIO(tt.pinNum)
if (err != nil) != tt.expectErr {
t.Errorf("ResolveGPIO(%s) error status mismatch: expected err=%t, got err=%v", tt.pinNum, tt.expectErr, err)
continue
}
if !tt.expectErr {
if port != tt.expectedPort || pin != tt.expectedPin {
t.Errorf("ResolveGPIO(%s) mismatch: expected port=%s pin=%d, got port=%s pin=%d", tt.pinNum, tt.expectedPort, tt.expectedPin, port, pin)
}
}
}
}
func TestITE82002_ResolveGPIO(t *testing.T) {
chip := getChipOrFatal(t, "it82002")
tests := []struct {
pinNum string
expectedPort string
expectedPin int
expectErr bool
}{
{"A10", "f", 2, false}, // PS2CLK1/DTR0#/SMINT8/GPF2
{"M6", "a", 2, false}, // PWM2/GPA2
{"N1", "d", 0, false}, // SMDAT2/RI1#/GPD0
{"A3", "b", 1, false}, // SOUT0/GPB1
{"A4", "b", 0, false}, // SIN0/GPB0
{"M8", "ksol", 0, false}, // KSO0/PD0
{"M13", "ksoh", 4, false}, // KSO12/SLCT
{"Z99", "", 0, true}, // Non-existent pin, should fail ResolveGPIO
}
for _, tt := range tests {
port, pin, err := chip.ResolveGPIO(tt.pinNum)
if (err != nil) != tt.expectErr {
t.Errorf("ResolveGPIO(%s) error status mismatch: expected err=%t, got err=%v", tt.pinNum, tt.expectErr, err)
continue
}
if !tt.expectErr {
if port != tt.expectedPort || pin != tt.expectedPin {
t.Errorf("ResolveGPIO(%s) mismatch: expected port=%s pin=%d, got port=%s pin=%d", tt.pinNum, tt.expectedPort, tt.expectedPin, port, pin)
}
}
}
}
func TestNPCX99_ResolveADC(t *testing.T) {
chip := getChipOrFatal(t, "npcx99")
tests := []struct {
pinNum string
expectedChan int
expectErr bool
}{
{"C2", 4, false}, // GPIO41/ADC4
{"D3", 3, false}, // GPIO42/ADC3/RI#
{"D10", 0, true}, // GPIOC6/SMI# (no ADC)
{"Z99", 0, true}, // Pin not found
}
for _, tt := range tests {
ch, err := chip.ResolveADC(tt.pinNum)
if (err != nil) != tt.expectErr {
t.Errorf("ResolveADC(%s) error status: expected err=%t, got %v", tt.pinNum, tt.expectErr, err)
continue
}
if !tt.expectErr && ch != tt.expectedChan {
t.Errorf("ResolveADC(%s) expected %d, got %d", tt.pinNum, tt.expectedChan, ch)
}
}
}
func TestITE82002_ResolvePWM(t *testing.T) {
chip := getChipOrFatal(t, "it82002")
tests := []struct {
pinNum string
expectedChan int
expectErr bool
}{
{"M6", 2, false}, // PWM2/GPA2
{"M7", 6, false}, // PWM6/SSCK/GPA6
{"M8", 0, true}, // KSO0/PD0 (no PWM)
{"Z99", 0, true}, // Pin not found
}
for _, tt := range tests {
ch, err := chip.ResolvePWM(tt.pinNum)
if (err != nil) != tt.expectErr {
t.Errorf("ResolvePWM(%s) error status: expected err=%t, got %v", tt.pinNum, tt.expectErr, err)
continue
}
if !tt.expectErr && ch != tt.expectedChan {
t.Errorf("ResolvePWM(%s) expected %d, got %d", tt.pinNum, tt.expectedChan, ch)
}
}
}
func TestChips_ResolveI2C(t *testing.T) {
npcx := getChipOrFatal(t, "npcx99")
ite := getChipOrFatal(t, "it82002")
it81202 := getChipOrFatal(t, "it81202")
it81302 := getChipOrFatal(t, "it81302")
tests := []struct {
chip *Chip
pinNum string
expectedChan string
expectedScl bool
expectErr bool
}{
// NPCX
{npcx, "B12", "0", false, false}, // GPIOB4/I2C0_SDA0
{npcx, "C12", "0", true, false}, // GPIOB5/I2C0_SCL0
{npcx, "A2", "", false, true}, // KSI0/GPIO31/TRACEDATA3/GP_MOSI (no I2C)
{npcx, "Z99", "", false, true}, // Pin not found
// ITE
{ite, "A5", "0", true, false}, // SMCLK0/GPB3
{ite, "A2", "0", false, false}, // SMDAT0/GPB4
{ite, "B1", "2ALT", true, false}, // SMCLK2ALT/PECI/GPF6
{ite, "C1", "2ALT", false, false}, // SMDAT2ALT/GPF7
{ite, "M8", "", false, true}, // KSO0/PD0 (no I2C)
// IT81202
{it81202, "M2", "2ALT", true, false}, // SMCLK2ALT
{it81202, "C1", "2ALT", false, false}, // SMDAT2ALT (prioritized over SMDAT2)
{it81202, "B1", "2", true, false}, // SMCLK2
// IT81302
{it81302, "N1", "2ALT", true, false}, // SMCLK2ALT
{it81302, "N15", "2ALT", false, false}, // SMDAT2ALT
}
for _, tt := range tests {
ch, scl, err := tt.chip.ResolveI2C(tt.pinNum)
if (err != nil) != tt.expectErr {
t.Errorf("[%s] ResolveI2C(%s) error status: expected err=%t, got %v", tt.chip.Name, tt.pinNum, tt.expectErr, err)
continue
}
if !tt.expectErr {
if ch != tt.expectedChan || scl != tt.expectedScl {
t.Errorf("[%s] ResolveI2C(%s) mismatch: expected chan=%s scl=%t, got chan=%s scl=%t", tt.chip.Name, tt.pinNum, tt.expectedChan, tt.expectedScl, ch, scl)
}
}
}
}
func TestChips_EmbeddedDataAndRegistration(t *testing.T) {
expectedChips := []string{"npcx99", "it81202", "it81302", "it82002", "it82202"}
for _, name := range expectedChips {
chip, ok := GetChip(name)
if !ok || chip == nil {
t.Errorf("Embedded chip %q missing from registered chips", name)
continue
}
if len(chip.PinMap) == 0 {
t.Errorf("Embedded chip %q has empty PinMap", name)
}
}
}
func TestITE_KSO_ResolveGPIO(t *testing.T) {
chip := &Chip{
Name: "it81302",
Vendor: "ite",
PinMap: map[string]string{
"P1": "KSO3",
"P2": "KSO12",
"P3": "KSO_INVALID",
"P4": "KSO16",
},
}
port, pin, err := chip.ResolveGPIO("P1")
if err != nil || port != "ksol" || pin != 3 {
t.Errorf("ResolveGPIO(P1 KSO3) expected port=ksol pin=3, got port=%s pin=%d err=%v", port, pin, err)
}
port, pin, err = chip.ResolveGPIO("P2")
if err != nil || port != "ksoh" || pin != 4 {
t.Errorf("ResolveGPIO(P2 KSO12) expected port=ksoh pin=4 (12-8), got port=%s pin=%d err=%v", port, pin, err)
}
_, _, err = chip.ResolveGPIO("P3")
if err == nil {
t.Error("Expected error for KSO_INVALID, got nil")
}
_, _, err = chip.ResolveGPIO("P4")
if err == nil {
t.Error("Expected error for KSO16, got nil")
}
}
func TestITE82202_FullResolution(t *testing.T) {
chip := getChipOrFatal(t, "it82202")
// ResolveGPIO
port, pin, err := chip.ResolveGPIO("M6") // PWM2/GPA2
if err != nil || port != "a" || pin != 2 {
t.Errorf("it82202 ResolveGPIO(M6) failed: port=%s pin=%d err=%v", port, pin, err)
}
// ResolvePWM
pwmChan, err := chip.ResolvePWM("M6")
if err != nil || pwmChan != 2 {
t.Errorf("it82202 ResolvePWM(M6) failed: pwm=%d err=%v", pwmChan, err)
}
// ResolveI2C
i2cChan, isScl, err := chip.ResolveI2C("B4") // SMCLK0/GPB3
if err != nil || i2cChan != "0" || !isScl {
t.Errorf("it82202 ResolveI2C(B4) failed: chan=%s isScl=%t err=%v", i2cChan, isScl, err)
}
}
func TestRegisterChipData_InvalidJSON(t *testing.T) {
err := RegisterChipData([]byte(`{invalid json`))
if err == nil {
t.Error("Expected error for invalid JSON, got nil")
}
}
func TestLoadExternalChipDir(t *testing.T) {
// Test non-existent directory
err := LoadExternalChipDir("non_existent_directory_xyz")
if err == nil {
t.Error("Expected error for non-existent directory, got nil")
}
// Test valid directory with a valid chip and an invalid chip
tmpDir, err := os.MkdirTemp("", "test_chips")
if err != nil {
t.Fatalf("Failed to create temp dir: %v", err)
}
defer os.RemoveAll(tmpDir)
// Write a valid chip JSON
validChipJSON := `{
"name": "temp-mock-chip",
"vendor": "mock",
"pin_map": {
"A1": "GPIOA1"
}
}`
err = os.WriteFile(filepath.Join(tmpDir, "temp_chip.json"), []byte(validChipJSON), 0644)
if err != nil {
t.Fatalf("Failed to write valid chip file: %v", err)
}
// Write an invalid chip JSON
invalidChipJSON := `{invalid json`
err = os.WriteFile(filepath.Join(tmpDir, "invalid_chip.json"), []byte(invalidChipJSON), 0644)
if err != nil {
t.Fatalf("Failed to write invalid chip file: %v", err)
}
// This should fail because of the invalid chip JSON
err = LoadExternalChipDir(tmpDir)
if err == nil {
t.Error("Expected error when loading directory with invalid JSON file, got nil")
}
// Remove the invalid chip and try again
err = os.Remove(filepath.Join(tmpDir, "invalid_chip.json"))
if err != nil {
t.Fatalf("Failed to remove invalid chip file: %v", err)
}
err = LoadExternalChipDir(tmpDir)
if err != nil {
t.Errorf("Expected success when loading valid chip directory, got error: %v", err)
}
// Verify the temp-mock-chip was registered
if _, ok := GetChip("temp-mock-chip"); !ok {
t.Error("temp-mock-chip was not registered")
}
}
func TestChips_ResolveTACH(t *testing.T) {
npcx := getChipOrFatal(t, "npcx99")
ite := getChipOrFatal(t, "it82002")
tests := []struct {
chip *Chip
pinNum string
expectedChan int
expectedPort string
expectErr bool
}{
// NPCX
{npcx, "E5", 1, "A", false}, // GPIO40/TA1
{npcx, "A2", 0, "", true}, // KSI0/GPIO31/TRACEDATA3/GP_MOSI (no TACH)
{npcx, "Z99", 0, "", true}, // Pin not found
// ITE
{ite, "M11", 0, "A", false}, // TACH0A/GPD6
{ite, "A10", 0, "", true}, // PS2CLK1/DTR0#/SMINT8/GPF2 (no TACH)
}
for _, tt := range tests {
ch, port, err := tt.chip.ResolveTACH(tt.pinNum)
if (err != nil) != tt.expectErr {
t.Errorf("%s ResolveTACH(%s) error status: expected err=%t, got %v", tt.chip.Name, tt.pinNum, tt.expectErr, err)
continue
}
if !tt.expectErr {
if ch != tt.expectedChan || port != tt.expectedPort {
t.Errorf("%s ResolveTACH(%s) expected chan=%d port=%s, got chan=%d port=%s", tt.chip.Name, tt.pinNum, tt.expectedChan, tt.expectedPort, ch, port)
}
}
}
}