[mt8167][gpio] Complete the list of pull regs settings
Also fix a check on ranges belonging to the GPIO registers set versus
the IOCFG set.
Test: runtests -t mtk-gpio-test and use MIC_MUTE/VOL- buttons on Cleo.
Change-Id: I9088550ee5e683e7ee9cbcf816868eb4eaca7451
diff --git a/system/dev/gpio/mt-8167/mt8167-gpio-regs.h b/system/dev/gpio/mt-8167/mt8167-gpio-regs.h
index 9becb87..be1a049 100644
--- a/system/dev/gpio/mt-8167/mt8167-gpio-regs.h
+++ b/system/dev/gpio/mt-8167/mt8167-gpio-regs.h
@@ -2,24 +2,56 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <ddktl/mmio.h>
-
#include <hwreg/bitfields.h>
-#include <hwreg/mmio.h>
-
+#include <soc/mt8167/mt8167-hw.h>
#include <zircon/types.h>
+// Define weak specialization methods that can be overridden in tests. There is a slight performance
+// hit as doing this prevents the MMIO accesses from being inlined.
+template <>
+template <>
+__WEAK uint16_t ddk::MmioBuffer::Read<uint16_t>(zx_off_t offs) const {
+ return Read<uint16_t>(offs);
+}
+
+template <>
+template <>
+__WEAK void ddk::MmioBuffer::Write<uint16_t>(uint16_t val, zx_off_t offs) const {
+ Write<uint16_t>(val, offs);
+}
+
+namespace {
+// There are 2 sets of GPIO Pull settings register banks, those under GPIO and those under IOCFG.
+// Those under the GPIO have a consistent numbering mapping such that the register offsets
+// can be calculated based on the GPIO number. The GPIOs that fall into IOCFG are marked as '0'
+// in kGpioPullInGpioRegs and return false in GpioPullEnReg/GpioPullSelReg methods to indicate that
+// they are not supported in the GPIO registers so we then try IoConfigReg methods. Note that the
+// last 3 GPIO numbers in the array don't fall under GPIO or IOCFG (as any other number past 127).
+static constexpr bool kGpioPullInGpioRegs[][16] = {
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0}, // 0 (first GPIO in this line).
+ {0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1}, // 16.
+ {1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1}, // 32.
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 48.
+ {1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1}, // 64.
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, // 80.
+ {1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0}, // 96.
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0}, // 112 (first is 112, last is 127).
+};
+
+} // namespace
+
namespace gpio {
-constexpr bool kGpioPullValid[][16] = {
- {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0},
- {0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1},
- {1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1},
- {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
- {1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1},
- {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
- {1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0},
- {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0},
+enum PullAmount {
+ kNoPull,
+ kPull10K,
+ kPull50K,
+ kPull10K50K,
+ kPull75K,
+ kPull2K,
+ kPull75K2K,
+ kPull200K,
+ kPull75K200K,
};
// GPIO MODE defines PINMUX for this device
@@ -131,7 +163,8 @@
private:
bool PullEnableInternal(size_t idx, bool val) const {
- if (idx >= countof(kGpioPullValid) || !kGpioPullValid[idx / 16][idx % 16]) {
+ if (idx >= sizeof(kGpioPullInGpioRegs) / sizeof(bool) ||
+ !kGpioPullInGpioRegs[idx / 16][idx % 16]) {
return false;
}
ModifyBit(idx, val);
@@ -148,7 +181,8 @@
private:
bool SetPullInternal(size_t idx, bool up) const {
- if (idx >= countof(kGpioPullValid) || !kGpioPullValid[idx / 16][idx % 16]) {
+ if (idx >= sizeof(kGpioPullInGpioRegs) / sizeof(bool) ||
+ !kGpioPullInGpioRegs[idx / 16][idx % 16]) {
return false;
}
ModifyBit(idx, up);
@@ -162,42 +196,89 @@
: ddk::MmioBuffer(mmio) {}
bool SetPullUp(size_t idx) const { return SetPullInternal(idx, true); }
bool SetPullDown(size_t idx) const { return SetPullInternal(idx, false); }
- bool PullEnable(size_t idx) const { return PullEnableInternal(idx, true); }
- bool PullDisable(size_t idx) const { return PullEnableInternal(idx, false); }
+ bool PullEnable(size_t idx, PullAmount amount) const { return PullEnableInternal(idx, amount); }
+ bool PullDisable(size_t idx) const { return PullEnableInternal(idx, kNoPull); }
private:
+ // This list pull settings not in the GPIO register set, but only here in IOCFG.
+ static constexpr struct {
+ size_t idx;
+ uint32_t reg_offset;
+ uint32_t up_down_bit;
+ uint32_t pull_bit_start;
+ PullAmount pull_amount_sets_reg_to_1;
+ PullAmount pull_amount_sets_reg_to_2;
+ PullAmount pull_amount_sets_reg_to_3;
+ } pull_regs[] = {
+ // clang-format off
+ { 14, 0x550, 14, 12, kPull10K, kPull50K, kPull10K50K},
+ { 15, 0x560, 2, 0, kPull10K, kPull50K, kPull10K50K},
+ { 16, 0x560, 6, 4, kPull10K, kPull50K, kPull10K50K},
+ { 17, 0x560, 10, 8, kPull10K, kPull50K, kPull10K50K},
+
+ { 21, 0x560, 14, 12, kPull10K, kPull50K, kPull10K50K},
+ { 22, 0x570, 2, 0, kPull10K, kPull50K, kPull10K50K},
+ { 23, 0x570, 6, 4, kPull10K, kPull50K, kPull10K50K},
+
+ { 40, 0x580, 2, 0, kPull75K, kPull2K, kPull75K2K},
+ { 41, 0x580, 6, 4, kPull75K, kPull2K, kPull75K2K},
+ { 42, 0x590, 2, 0, kPull75K, kPull200K, kPull75K200K},
+ { 43, 0x590, 6, 4, kPull75K, kPull200K, kPull75K200K},
+
+ { 68, 0x550, 10, 8, kPull10K, kPull50K, kPull10K50K},
+ { 69, 0x550, 6, 4, kPull10K, kPull50K, kPull10K50K},
+ { 70, 0x540, 6, 4, kPull10K, kPull50K, kPull10K50K},
+ { 71, 0x540, 10, 8, kPull10K, kPull50K, kPull10K50K},
+ { 72, 0x540, 14, 12, kPull10K, kPull50K, kPull10K50K},
+ { 73, 0x550, 2, 0, kPull10K, kPull50K, kPull10K50K},
+
+ { 104, 0x540, 2, 0, kPull10K, kPull50K, kPull10K50K},
+ { 105, 0x530, 14, 12, kPull10K, kPull50K, kPull10K50K},
+ { 106, 0x520, 14, 12, kPull10K, kPull50K, kPull10K50K},
+ { 107, 0x530, 2, 0, kPull10K, kPull50K, kPull10K50K},
+ { 108, 0x530, 6, 4, kPull10K, kPull50K, kPull10K50K},
+ { 109, 0x530, 10, 8, kPull10K, kPull50K, kPull10K50K},
+ { 110, 0x510, 14, 12, kPull10K, kPull50K, kPull10K50K},
+ { 111, 0x510, 10, 8, kPull10K, kPull50K, kPull10K50K},
+ { 112, 0x510, 6, 4, kPull10K, kPull50K, kPull10K50K},
+ { 113, 0x510, 2, 0, kPull10K, kPull50K, kPull10K50K},
+ { 114, 0x520, 10, 8, kPull10K, kPull50K, kPull10K50K},
+ { 115, 0x520, 2, 0, kPull10K, kPull50K, kPull10K50K},
+ { 116, 0x520, 6, 4, kPull10K, kPull50K, kPull10K50K},
+ { 117, 0x500, 14, 12, kPull10K, kPull50K, kPull10K50K},
+ { 118, 0x500, 10, 8, kPull10K, kPull50K, kPull10K50K},
+ { 119, 0x500, 6, 4, kPull10K, kPull50K, kPull10K50K},
+ { 120, 0x500, 2, 0, kPull10K, kPull50K, kPull10K50K},
+ // clang-format on
+ };
+
bool SetPullInternal(size_t idx, bool up) const {
- switch (idx) {
- case 40:
- ModifyBit<uint32_t>(!up, 2, 0x580);
- return true;
- case 41:
- ModifyBit<uint32_t>(!up, 6, 0x580);
- return true;
- case 42:
- ModifyBit<uint32_t>(!up, 2, 0x590);
- return true;
- case 43:
- ModifyBit<uint32_t>(!up, 6, 0x590);
- return true;
+ for (auto& i : pull_regs) {
+ if (i.idx == idx) {
+ ModifyBit<uint16_t>(!up, i.up_down_bit, i.reg_offset);
+ return true;
+ }
}
return false;
}
- bool PullEnableInternal(size_t idx, bool enable) const {
- constexpr uint32_t r75K = 1;
- switch (idx) {
- case 40:
- ModifyBits(enable ? r75K : 0, 0, 2, 0x580);
- return true;
- case 41:
- ModifyBits(enable ? r75K : 0, 4, 2, 0x580);
- return true;
- case 42:
- ModifyBits(enable ? r75K : 0, 0, 2, 0x590);
- return true;
- case 43:
- ModifyBits(enable ? r75K : 0, 4, 2, 0x590);
- return true;
+ bool PullEnableInternal(size_t idx, PullAmount pull) const {
+ for (auto& i : pull_regs) {
+ if (i.idx == idx) {
+ uint16_t val;
+ if (pull == kNoPull) {
+ val = 0;
+ } else if (pull == i.pull_amount_sets_reg_to_1) {
+ val = 1;
+ } else if (pull == i.pull_amount_sets_reg_to_2) {
+ val = 2;
+ } else if (pull == i.pull_amount_sets_reg_to_3) {
+ val = 3;
+ } else {
+ return false; // Not supported pull amount for this GPIO.
+ }
+ ModifyBits<uint16_t>(val, i.pull_bit_start, 2, i.reg_offset);
+ return true;
+ }
}
return false;
}
diff --git a/system/dev/gpio/mt-8167/mt8167-gpio-test.cpp b/system/dev/gpio/mt-8167/mt8167-gpio-test.cpp
new file mode 100644
index 0000000..d884a90
--- /dev/null
+++ b/system/dev/gpio/mt-8167/mt8167-gpio-test.cpp
@@ -0,0 +1,219 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "mt8167-gpio.h"
+
+#include <ddktl/mmio.h>
+#include <fbl/auto_call.h>
+#include <lib/fake_ddk/fake_ddk.h>
+#include <mock-mmio-reg/mock-mmio-reg.h>
+
+namespace {
+constexpr size_t kGpioRegCount = MT8167_GPIO_SIZE / sizeof(uint16_t);
+constexpr size_t kIoCfgRegCount = MT8167_IOCFG_SIZE / sizeof(uint16_t);
+} // namespace
+
+namespace gpio {
+
+class Mt8167GpioDeviceTest : public Mt8167GpioDevice {
+public:
+ explicit Mt8167GpioDeviceTest(ddk_mock::MockMmioRegRegion& gpio_regs,
+ ddk_mock::MockMmioRegRegion& registers1,
+ ddk_mock::MockMmioRegRegion& registers2)
+ : Mt8167GpioDevice(nullptr,
+ gpio_regs.GetMmioBuffer(),
+ registers1.GetMmioBuffer(),
+ registers2.GetMmioBuffer()) {
+ // Fake interrupts fooling GPIO's checks, not used in these tests.
+ interrupts_ = fbl::Array(new zx::interrupt[MT8167_GPIO_EINT_MAX], MT8167_GPIO_EINT_MAX);
+ }
+};
+
+bool TestNoPull0() {
+ BEGIN_TEST;
+
+ fbl::Array<ddk_mock::MockMmioReg> gpio_regs =
+ fbl::Array(new ddk_mock::MockMmioReg[kGpioRegCount], kGpioRegCount);
+ ddk_mock::MockMmioRegRegion gpios_mock(gpio_regs.get(), sizeof(uint16_t), kGpioRegCount);
+ ddk_mock::MockMmioRegRegion unused(nullptr, sizeof(uint16_t), kGpioRegCount);
+ Mt8167GpioDeviceTest gpio(gpios_mock, unused, unused);
+
+ gpios_mock[0x300].ExpectRead(0xFFFF).ExpectWrite(0xFFF8); // 3 GPIO_MODE1 bits for GPIO mode.
+ gpios_mock[0x000].ExpectRead(0xFFFF).ExpectWrite(0xFFFE); // GPIO_DIR1 bit 0 to input (0).
+ gpios_mock[0x500].ExpectRead(0xFFFF).ExpectWrite(0xFFFE); // GPIO_PULLEN1 bit 0 to disabled (0).
+ EXPECT_EQ(gpio.GpioImplConfigIn(0, GPIO_NO_PULL), ZX_OK);
+ gpios_mock.VerifyAll();
+
+ END_TEST;
+}
+
+bool TestNoPullMid() {
+ BEGIN_TEST;
+
+ fbl::Array<ddk_mock::MockMmioReg> gpio_regs =
+ fbl::Array(new ddk_mock::MockMmioReg[kGpioRegCount], kGpioRegCount);
+ ddk_mock::MockMmioRegRegion gpios_mock(gpio_regs.get(), sizeof(uint16_t), kGpioRegCount);
+ ddk_mock::MockMmioRegRegion unused(nullptr, sizeof(uint16_t), kGpioRegCount);
+ Mt8167GpioDeviceTest gpio(gpios_mock, unused, unused);
+
+ gpios_mock[0x3D0].ExpectRead(0xFFFF).ExpectWrite(0xFE3F); // 3 GPIO_MODEE bits for GPIO mode.
+ gpios_mock[0x040].ExpectRead(0xFFFF).ExpectWrite(0xFFF7); // GPIO_DIR5 bit 0 to input (0).
+ gpios_mock[0x540].ExpectRead(0xFFFF).ExpectWrite(0xFFF7); // GPIO_PULLEN5 bit 0 to disabled (0).
+ EXPECT_EQ(gpio.GpioImplConfigIn(67, GPIO_NO_PULL), ZX_OK);
+ gpios_mock.VerifyAll();
+
+ END_TEST;
+}
+
+bool TestNoPullHigh() {
+ BEGIN_TEST;
+
+ fbl::Array<ddk_mock::MockMmioReg> gpio_regs =
+ fbl::Array(new ddk_mock::MockMmioReg[kGpioRegCount], kGpioRegCount);
+ ddk_mock::MockMmioRegRegion gpios_mock(gpio_regs.get(), sizeof(uint16_t), kGpioRegCount);
+ ddk_mock::MockMmioRegRegion unused(nullptr, sizeof(uint16_t), kGpioRegCount);
+ Mt8167GpioDeviceTest gpio(gpios_mock, unused, unused);
+
+ gpios_mock[0x480].ExpectRead(0xFFFF).ExpectWrite(0x8FFF); // 3 GPIO_MODE19 bits for GPIO mode.
+ gpios_mock[0x070].ExpectRead(0xFFFF).ExpectWrite(0xEFFF); // GPIO_DIR8 bit 0 to input (0).
+ gpios_mock[0x570].ExpectRead(0xFFFF).ExpectWrite(0xEFFF); // GPIO_PULLEN8 bit 0 to disabled (0).
+ EXPECT_EQ(gpio.GpioImplConfigIn(124, GPIO_NO_PULL), ZX_OK);
+ gpios_mock.VerifyAll();
+
+ END_TEST;
+}
+
+bool TestOutOfRange() {
+ BEGIN_TEST;
+
+ ddk_mock::MockMmioRegRegion unused(nullptr, sizeof(uint16_t), kGpioRegCount);
+ Mt8167GpioDeviceTest gpio(unused, unused, unused);
+
+ EXPECT_EQ(gpio.GpioImplConfigIn(kGpioRegCount, GPIO_NO_PULL), ZX_ERR_INVALID_ARGS);
+
+ END_TEST;
+}
+
+bool TestPullUp() {
+ BEGIN_TEST;
+
+ fbl::Array<ddk_mock::MockMmioReg> gpio_regs =
+ fbl::Array(new ddk_mock::MockMmioReg[kGpioRegCount], kGpioRegCount);
+ ddk_mock::MockMmioRegRegion gpios_mock(gpio_regs.get(), sizeof(uint16_t), kGpioRegCount);
+ ddk_mock::MockMmioRegRegion unused(nullptr, sizeof(uint16_t), kGpioRegCount);
+ Mt8167GpioDeviceTest gpio(gpios_mock, unused, unused);
+
+ gpios_mock[0x360].ExpectRead(0xFFFF).ExpectWrite(0xF1FF); // 3 GPIO_MODE7 bits for GPIO mode.
+ gpios_mock[0x020].ExpectRead(0xFFFF).ExpectWrite(0xFFFD); // GPIO_DIR3 bit 0 to input (0).
+ gpios_mock[0x520].ExpectRead(0x0000).ExpectWrite(0x0002); // GPIO_PULLEN3 bit 0 to enable (1).
+ gpios_mock[0x620].ExpectRead(0x0000).ExpectWrite(0x0002); // GPIO_PULLSEL3 bit 0 to up (1).
+ EXPECT_EQ(gpio.GpioImplConfigIn(33, GPIO_PULL_UP), ZX_OK);
+ gpios_mock.VerifyAll();
+
+ END_TEST;
+}
+
+bool TestPullDown() {
+ BEGIN_TEST;
+
+ fbl::Array<ddk_mock::MockMmioReg> gpio_regs =
+ fbl::Array(new ddk_mock::MockMmioReg[kGpioRegCount], kGpioRegCount);
+ ddk_mock::MockMmioRegRegion gpios_mock(gpio_regs.get(), sizeof(uint16_t), kGpioRegCount);
+ ddk_mock::MockMmioRegRegion unused(nullptr, sizeof(uint16_t), kGpioRegCount);
+ Mt8167GpioDeviceTest gpio(gpios_mock, unused, unused);
+
+ gpios_mock[0x360].ExpectRead(0xFFFF).ExpectWrite(0xFE3F); // 3 GPIO_MODE7 bits for GPIO mode.
+ gpios_mock[0x020].ExpectRead(0xFFFF).ExpectWrite(0xFFFE); // GPIO_DIR3 bit 0 to input (0).
+ gpios_mock[0x520].ExpectRead(0x0000).ExpectWrite(0x0001); // GPIO_PULLEN3 bit 0 to enable (1).
+ gpios_mock[0x620].ExpectRead(0xFFFF).ExpectWrite(0xFFFE); // GPIO_PULLSEL3 bit 0 to down (0).
+ EXPECT_EQ(gpio.GpioImplConfigIn(32, GPIO_PULL_DOWN), ZX_OK);
+ gpios_mock.VerifyAll();
+
+ END_TEST;
+}
+
+bool TestNoPullIoCfg() {
+ BEGIN_TEST;
+
+ fbl::Array<ddk_mock::MockMmioReg> gpio_regs =
+ fbl::Array(new ddk_mock::MockMmioReg[kGpioRegCount], kGpioRegCount);
+ fbl::Array<ddk_mock::MockMmioReg> iocfg_regs =
+ fbl::Array(new ddk_mock::MockMmioReg[kIoCfgRegCount], kIoCfgRegCount);
+ ddk_mock::MockMmioRegRegion gpios_mock(gpio_regs.get(), sizeof(uint16_t), kGpioRegCount);
+ ddk_mock::MockMmioRegRegion iocfg_mock(iocfg_regs.get(), sizeof(uint16_t), kIoCfgRegCount);
+ ddk_mock::MockMmioRegRegion unused(nullptr, sizeof(uint16_t), 1); // Fake non-zero size.
+ Mt8167GpioDeviceTest gpio(gpios_mock, iocfg_mock, unused);
+
+ gpios_mock[0x330].ExpectRead(0xFFFF).ExpectWrite(0xFFF8); // 3 GPIO_MODE4 bits for GPIO mode.
+ gpios_mock[0x000].ExpectRead(0xFFFF).ExpectWrite(0x7FFF); // GPIO_DIR1 bit 15 to input (0).
+ iocfg_mock[0x560].ExpectRead(0xFFFF).ExpectWrite(0xFFFC); // PUPD_CTRL6 bits 0-1 to no pull (0).
+ EXPECT_EQ(gpio.GpioImplConfigIn(15, GPIO_NO_PULL), ZX_OK);
+ gpios_mock.VerifyAll();
+ iocfg_mock.VerifyAll();
+
+ END_TEST;
+}
+
+bool TestPullUpIoCfg() {
+ BEGIN_TEST;
+
+ fbl::Array<ddk_mock::MockMmioReg> gpio_regs =
+ fbl::Array(new ddk_mock::MockMmioReg[kGpioRegCount], kGpioRegCount);
+ fbl::Array<ddk_mock::MockMmioReg> iocfg_regs =
+ fbl::Array(new ddk_mock::MockMmioReg[kIoCfgRegCount], kIoCfgRegCount);
+ ddk_mock::MockMmioRegRegion gpios_mock(gpio_regs.get(), sizeof(uint16_t), kGpioRegCount);
+ ddk_mock::MockMmioRegRegion iocfg_mock(iocfg_regs.get(), sizeof(uint16_t), kIoCfgRegCount);
+ ddk_mock::MockMmioRegRegion unused(nullptr, sizeof(uint16_t), 1); // Fake non-zero size.
+ Mt8167GpioDeviceTest gpio(gpios_mock, iocfg_mock, unused);
+
+ gpios_mock[0x330].ExpectRead(0xFFFF).ExpectWrite(0xFFF8); // 3 GPIO_MODE4 bits for GPIO mode.
+ gpios_mock[0x000].ExpectRead(0xFFFF).ExpectWrite(0x7FFF); // GPIO_DIR1 bit 15 to input (0).
+ iocfg_mock[0x560].ExpectRead(0x0000).ExpectWrite(0x0001); // PUPD_CTRL6 bits 0-1 pull 10K (1).
+ iocfg_mock[0x560].ExpectRead(0xFFFF).ExpectWrite(0xFFFB); // PUPD_CTRL6 bit 2 to pull up (0).
+ EXPECT_EQ(gpio.GpioImplConfigIn(15, GPIO_PULL_UP), ZX_OK);
+ gpios_mock.VerifyAll();
+ iocfg_mock.VerifyAll();
+
+ END_TEST;
+}
+
+bool TestPullDownIoCfg() {
+ BEGIN_TEST;
+
+ fbl::Array<ddk_mock::MockMmioReg> gpio_regs =
+ fbl::Array(new ddk_mock::MockMmioReg[kGpioRegCount], kGpioRegCount);
+ fbl::Array<ddk_mock::MockMmioReg> iocfg_regs =
+ fbl::Array(new ddk_mock::MockMmioReg[kIoCfgRegCount], kIoCfgRegCount);
+ ddk_mock::MockMmioRegRegion gpios_mock(gpio_regs.get(), sizeof(uint16_t), kGpioRegCount);
+ ddk_mock::MockMmioRegRegion iocfg_mock(iocfg_regs.get(), sizeof(uint16_t), kIoCfgRegCount);
+ ddk_mock::MockMmioRegRegion unused(nullptr, sizeof(uint16_t), 1); // Fake non-zero size.
+ Mt8167GpioDeviceTest gpio(gpios_mock, iocfg_mock, unused);
+
+ gpios_mock[0x330].ExpectRead(0xFFFF).ExpectWrite(0xFFF8); // 3 GPIO_MODE4 bits for GPIO mode.
+ gpios_mock[0x000].ExpectRead(0xFFFF).ExpectWrite(0x7FFF); // GPIO_DIR1 bit 15 to input (0).
+ iocfg_mock[0x560].ExpectRead(0x0000).ExpectWrite(0x0001); // PUPD_CTRL6 bits 0-1 pull 10K (1).
+ iocfg_mock[0x560].ExpectRead(0x0000).ExpectWrite(0x0004); // PUPD_CTRL6 bit 2 to pull down (1).
+ EXPECT_EQ(gpio.GpioImplConfigIn(15, GPIO_PULL_DOWN), ZX_OK);
+ gpios_mock.VerifyAll();
+ iocfg_mock.VerifyAll();
+
+ END_TEST;
+}
+} // namespace gpio
+
+int main(int argc, char** argv) {
+ return unittest_run_all_tests(argc, argv) ? 0 : 1;
+}
+
+BEGIN_TEST_CASE(MtkGpioTests)
+RUN_TEST_SMALL(gpio::TestNoPull0)
+RUN_TEST_SMALL(gpio::TestNoPullMid)
+RUN_TEST_SMALL(gpio::TestNoPullHigh)
+RUN_TEST_SMALL(gpio::TestOutOfRange)
+RUN_TEST_SMALL(gpio::TestPullUp)
+RUN_TEST_SMALL(gpio::TestPullDown)
+RUN_TEST_SMALL(gpio::TestNoPullIoCfg)
+RUN_TEST_SMALL(gpio::TestPullUpIoCfg)
+RUN_TEST_SMALL(gpio::TestPullDownIoCfg)
+END_TEST_CASE(MtkGpioTests)
diff --git a/system/dev/gpio/mt-8167/mt8167-gpio.cpp b/system/dev/gpio/mt-8167/mt8167-gpio.cpp
index 51c365c..869aaca 100644
--- a/system/dev/gpio/mt-8167/mt8167-gpio.cpp
+++ b/system/dev/gpio/mt-8167/mt8167-gpio.cpp
@@ -8,20 +8,13 @@
#include <ddk/binding.h>
#include <ddk/debug.h>
#include <ddk/device.h>
-#include <ddk/protocol/gpioimpl.h>
-
#include <fbl/alloc_checker.h>
-#include <fbl/auto_call.h>
#include <fbl/unique_ptr.h>
-
#include <hw/reg.h>
-
#include <soc/mt8167/mt8167-hw.h>
-
#include <zircon/syscalls/port.h>
#include <zircon/types.h>
-#include "mt8167-gpio-regs.h"
#include "mt8167-gpio.h"
namespace gpio {
@@ -80,6 +73,13 @@
}
// If not supported above, try IO Config.
+ // TODO(andresoportus): We only support enable/disable pull through the GPIO protocol, so
+ // until we allow passing particular pull amounts we can specify here different pull amounts
+ // for particular GPIOs.
+ PullAmount pull_amount = kPull10K;
+ if (index >= 40 && index <= 43) {
+ pull_amount = kPull75K;
+ }
switch (pull_mode) {
case GPIO_NO_PULL:
if (iocfg_.PullDisable(index)) {
@@ -87,12 +87,12 @@
}
break;
case GPIO_PULL_UP:
- if (iocfg_.PullEnable(index) && iocfg_.SetPullUp(index)) {
+ if (iocfg_.PullEnable(index, pull_amount) && iocfg_.SetPullUp(index)) {
return ZX_OK;
}
break;
case GPIO_PULL_DOWN:
- if (iocfg_.PullEnable(index) && iocfg_.SetPullDown(index)) {
+ if (iocfg_.PullEnable(index, pull_amount) && iocfg_.SetPullDown(index)) {
return ZX_OK;
}
break;
@@ -352,4 +352,3 @@
}
} // namespace gpio
-
diff --git a/system/dev/gpio/mt-8167/mt8167-gpio.h b/system/dev/gpio/mt-8167/mt8167-gpio.h
index 61da384..d45296e 100644
--- a/system/dev/gpio/mt-8167/mt8167-gpio.h
+++ b/system/dev/gpio/mt-8167/mt8167-gpio.h
@@ -4,23 +4,20 @@
#pragma once
-#include <ddk/platform-defs.h>
-#include <ddk/protocol/gpioimpl.h>
-#include <ddk/protocol/platform/bus.h>
-#include <ddk/protocol/platform-device-lib.h>
-#include <ddk/protocol/platform/device.h>
+#include <threads.h>
+#include <ddk/platform-defs.h>
+#include <ddk/protocol/platform-device-lib.h>
+#include <ddk/protocol/platform/bus.h>
+#include <ddk/protocol/platform/device.h>
#include <ddktl/device.h>
#include <ddktl/protocol/gpioimpl.h>
-
#include <fbl/array.h>
-
-#include <hw/reg.h>
-#include <hwreg/mmio.h>
-
#include <lib/zx/interrupt.h>
#include <lib/zx/port.h>
+#include "mt8167-gpio-regs.h"
+
namespace gpio {
class Mt8167GpioDevice;
@@ -59,6 +56,9 @@
zx_status_t GpioImplReleaseInterrupt(uint32_t index);
zx_status_t GpioImplSetPolarity(uint32_t index, uint32_t polarity);
+protected:
+ fbl::Array<zx::interrupt> interrupts_; // Protected to be changed in unit tests.
+
private:
void ShutDown();
int Thread();
@@ -74,6 +74,5 @@
zx::interrupt int_;
zx::port port_;
thrd_t thread_;
- fbl::Array<zx::interrupt> interrupts_;
};
} // namespace gpio
diff --git a/system/dev/gpio/mt-8167/rules.mk b/system/dev/gpio/mt-8167/rules.mk
index ed01982..949e5cf 100644
--- a/system/dev/gpio/mt-8167/rules.mk
+++ b/system/dev/gpio/mt-8167/rules.mk
@@ -35,3 +35,40 @@
MODULE_HEADER_DEPS := system/dev/lib/mt8167
include make/module.mk
+
+MODULE := $(LOCAL_DIR).test
+
+MODULE_NAME := mtk-gpio-test
+
+MODULE_TYPE := usertest
+
+MODULE_SRCS += \
+ $(LOCAL_DIR)/test-overrides.cpp \
+ $(LOCAL_DIR)/mt8167-gpio-test.cpp \
+ $(LOCAL_DIR)/mt8167-gpio.cpp \
+
+MODULE_STATIC_LIBS := \
+ system/dev/lib/mt8167 \
+ system/dev/lib/fake_ddk \
+ system/dev/lib/mock-mmio-reg \
+ system/ulib/ddk \
+ system/ulib/ddktl \
+ system/ulib/fbl \
+ system/ulib/hwreg \
+ system/ulib/sync \
+ system/ulib/zx \
+ system/ulib/zxcpp \
+
+MODULE_LIBS := \
+ system/ulib/driver \
+ system/ulib/c \
+ system/ulib/unittest \
+ system/ulib/zircon \
+
+MODULE_BANJO_LIBS := \
+ system/banjo/ddk-protocol-gpio \
+ system/banjo/ddk-protocol-gpioimpl \
+ system/banjo/ddk-protocol-platform-bus \
+ system/banjo/ddk-protocol-platform-device \
+
+include make/module.mk
diff --git a/system/dev/gpio/mt-8167/test-overrides.cpp b/system/dev/gpio/mt-8167/test-overrides.cpp
new file mode 100644
index 0000000..2d0eddd
--- /dev/null
+++ b/system/dev/gpio/mt-8167/test-overrides.cpp
@@ -0,0 +1,28 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <ddktl/mmio.h>
+#include <mock-mmio-reg/mock-mmio-reg.h>
+
+// These override the weak methods in mt8167-gpio-regs.h.
+// mock-mmio uses vaddr as a key to find MockMmioRegRegion, need to substract offset.
+template <>
+template <>
+uint16_t ddk::MmioBuffer::Read<uint16_t>(zx_off_t offs) const {
+ ddk_mock::MockMmioRegRegion* mock_regs =
+ reinterpret_cast<ddk_mock::MockMmioRegRegion*>(
+ reinterpret_cast<uintptr_t>(mmio_.vaddr) - mmio_.offset);
+ ZX_ASSERT(mock_regs != nullptr);
+ return static_cast<uint16_t>((*mock_regs)[mmio_.offset + offs].Read());
+}
+
+template <>
+template <>
+void ddk::MmioBuffer::Write<uint16_t>(uint16_t val, zx_off_t offs) const {
+ ddk_mock::MockMmioRegRegion* mock_regs =
+ reinterpret_cast<ddk_mock::MockMmioRegRegion*>(
+ reinterpret_cast<uintptr_t>(mmio_.vaddr) - mmio_.offset);
+ ZX_ASSERT(mock_regs != nullptr);
+ (*mock_regs)[mmio_.offset + offs].Write(val);
+}