aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLee Campbell <leecam@google.com>2016-03-03 13:34:39 -0800
committerLee Campbell <leecam@google.com>2016-03-03 14:02:57 -0800
commit2f7e32cd7e127d36a09a85d8da612f3f7f8713d5 (patch)
tree2437dcbbe71c5a3de87ba7314bf5d65e40dbe3d7
parent52373993181972ec6629d0c4e39ef86d448799d5 (diff)
downloadperipheralmanager-2f7e32cd7e127d36a09a85d8da612f3f7f8713d5.tar.gz
Add SPI Manager
Add SPI backend and fake device stubs for unit testing. BUG: 26779252 Change-Id: I33607d7a266f53a63452bd7a1757a22d9f21e97a
-rw-r--r--daemon/Android.mk6
-rw-r--r--daemon/fake_devices.cc51
-rw-r--r--daemon/fake_devices.h42
-rw-r--r--daemon/spi_manager.cc115
-rw-r--r--daemon/spi_manager.h116
-rw-r--r--daemon/spi_manager_unittest.cc77
6 files changed, 407 insertions, 0 deletions
diff --git a/daemon/Android.mk b/daemon/Android.mk
index c3dac65..9e5e79e 100644
--- a/daemon/Android.mk
+++ b/daemon/Android.mk
@@ -71,12 +71,14 @@ LOCAL_SHARED_LIBRARIES := \
$(peripheralman_CommonSharedLibraries) \
LOCAL_SRC_FILES := \
+ char_device.cc \
gpio_driver_sysfs.cc \
gpio_manager.cc \
peripheral_manager.cc \
peripheral_manager_client.cc \
pin_mux_manager.cc \
spi_driver_spidev.cc \
+ spi_manager.cc \
include $(BUILD_STATIC_LIBRARY)
@@ -95,10 +97,12 @@ LOCAL_STATIC_LIBRARIES := \
peripheral_manager_hal_headers \
LOCAL_SRC_FILES := \
+ char_device.cc \
gpio_driver_sysfs.cc \
gpio_manager.cc \
pin_mux_manager.cc \
spi_driver_spidev.cc \
+ spi_manager.cc \
include $(BUILD_HOST_STATIC_LIBRARY)
@@ -117,7 +121,9 @@ LOCAL_SHARED_LIBRARIES := \
libchrome \
LOCAL_SRC_FILES := \
+ fake_devices.cc \
gpio_manager_unittest.cc \
pin_mux_manager_unittest.cc \
+ spi_manager_unittest.cc \
include $(BUILD_HOST_NATIVE_TEST)
diff --git a/daemon/fake_devices.cc b/daemon/fake_devices.cc
new file mode 100644
index 0000000..20a4258
--- /dev/null
+++ b/daemon/fake_devices.cc
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#include "fake_devices.h"
+
+#include <stdio.h>
+
+namespace android {
+
+FakeCharDevice::FakeCharDevice() {}
+FakeCharDevice::~FakeCharDevice() {}
+
+// TODO(leecam): Implement these.
+int FakeCharDevice::Open(const char* pathname, int flags) {
+ return 1;
+}
+
+int FakeCharDevice::Close(int fd) {
+ return 0;
+}
+
+int FakeCharDevice::Ioctl(int fd, int request, void* argp) {
+ return 0;
+}
+
+ssize_t FakeCharDevice::Read(int fd, void* buf, size_t count) {
+ return 0;
+}
+
+ssize_t FakeCharDevice::Write(int fd, const void* buf, size_t count) {
+ return 0;
+}
+
+int FakeCharDevice::Poll(struct pollfd* fds, nfds_t nfds, int timeout) {
+ return 0;
+}
+
+} // namespace android
diff --git a/daemon/fake_devices.h b/daemon/fake_devices.h
new file mode 100644
index 0000000..56d57a0
--- /dev/null
+++ b/daemon/fake_devices.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#ifndef SYSTEM_PERIPHERALMANAGER_DAEMON_FAKE_DEVICES_H_
+#define SYSTEM_PERIPHERALMANAGER_DAEMON_FAKE_DEVICES_H_
+
+#include <string>
+#include <vector>
+
+#include "char_device.h"
+
+namespace android {
+
+class FakeCharDevice : public CharDeviceInterface {
+ public:
+ FakeCharDevice();
+ ~FakeCharDevice() override;
+
+ int Open(const char* pathname, int flags) override;
+ int Close(int fd) override;
+ int Ioctl(int fd, int request, void* argp) override;
+ ssize_t Read(int fd, void* buf, size_t count) override;
+ ssize_t Write(int fd, const void* buf, size_t count) override;
+ int Poll(struct pollfd* fds, nfds_t nfds, int timeout) override;
+};
+
+} // namespace android
+
+#endif // SYSTEM_PERIPHERALMANAGER_DAEMON_FAKE_DEVICES_H_ \ No newline at end of file
diff --git a/daemon/spi_manager.cc b/daemon/spi_manager.cc
new file mode 100644
index 0000000..3afb45c
--- /dev/null
+++ b/daemon/spi_manager.cc
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#include "spi_manager.h"
+
+#include "pin_mux_manager.h"
+
+namespace android {
+
+std::unique_ptr<SpiManager> g_spi_manager;
+
+SpiManager::SpiManager() {}
+
+SpiManager::~SpiManager() {}
+
+// static
+SpiManager* SpiManager::GetSpiManager() {
+ if (!g_spi_manager) {
+ g_spi_manager.reset(new SpiManager());
+ }
+ return g_spi_manager.get();
+}
+
+bool SpiManager::RegisterSpiDevBus(const std::string& name,
+ uint32_t bus,
+ uint32_t cs) {
+ if (spidev_buses_.count(name))
+ return false;
+ spidev_buses_.emplace(name, SpiDevBus(bus, cs));
+ return true;
+}
+
+std::vector<std::string> SpiManager::GetSpiDevBusses() {
+ std::vector<std::string> buses;
+ for (auto& i : spidev_buses_)
+ buses.push_back(i.first);
+ return buses;
+}
+
+bool SpiManager::RegisterDriver(
+ std::unique_ptr<SpiDriverInfoBase> driver_info) {
+ std::string key = driver_info->Compat();
+ driver_infos_[key] = std::move(driver_info);
+ return true;
+}
+
+bool SpiManager::SetPinMux(const std::string& name, const std::string& mux) {
+ auto bus_it = spidev_buses_.find(name);
+ if (bus_it == spidev_buses_.end())
+ return false;
+ bus_it->second.mux = mux;
+ bus_it->second.mux_group = mux;
+ return true;
+}
+
+bool SpiManager::SetPinMuxWithGroup(const std::string& name,
+ const std::string& mux,
+ const std::string& group) {
+ auto bus_it = spidev_buses_.find(name);
+ if (bus_it == spidev_buses_.end())
+ return false;
+ bus_it->second.mux = mux;
+ bus_it->second.mux_group = group;
+ return true;
+}
+
+std::unique_ptr<SpiDevice> SpiManager::OpenSpiDevice(const std::string& name) {
+ // Get the Bus from the BSP.
+ auto bus_it = spidev_buses_.find(name);
+ if (bus_it == spidev_buses_.end())
+ return nullptr;
+
+ // Check its not alread in use
+ if (bus_it->second.driver_) {
+ return nullptr;
+ }
+
+ // Find a driver.
+ // Currently there is only hardcoded support for SPIDEV
+ auto driver_info_it = driver_infos_.find("SPIDEV");
+
+ // Fail if there is no driver.
+ if (driver_info_it == driver_infos_.end())
+ return nullptr;
+
+ std::unique_ptr<SpiDriverInterface> driver(driver_info_it->second->Probe());
+
+ if (!driver->Init(bus_it->second.bus, bus_it->second.cs))
+ return nullptr;
+
+ // Set Pin muxing.
+ if (!bus_it->second.mux.empty()) {
+ PinMuxManager::GetPinMuxManager()->SetSource(bus_it->second.mux,
+ bus_it->second.mux_group);
+ }
+
+ bus_it->second.driver_ = std::move(driver);
+
+ return std::unique_ptr<SpiDevice>(new SpiDevice(&(bus_it->second)));
+}
+
+} // namespace android
diff --git a/daemon/spi_manager.h b/daemon/spi_manager.h
new file mode 100644
index 0000000..609f38e
--- /dev/null
+++ b/daemon/spi_manager.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#ifndef SYSTEM_PERIPHERALMANAGER_DAEMON_SPI_MANAGER_H_
+#define SYSTEM_PERIPHERALMANAGER_DAEMON_SPI_MANAGER_H_
+
+#include <stdint.h>
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <base/macros.h>
+
+#include "pin_mux_manager.h"
+#include "spi_driver.h"
+
+namespace android {
+
+struct SpiDevBus {
+ SpiDevBus(uint32_t b, uint32_t c) : bus(b), cs(c) {}
+ uint32_t bus;
+ uint32_t cs;
+ std::string mux;
+ std::string mux_group;
+ std::unique_ptr<SpiDriverInterface> driver_;
+};
+
+class SpiDevice {
+ public:
+ SpiDevice(SpiDevBus* bus) : bus_(bus) {}
+ ~SpiDevice() {
+ if (!bus_->mux.empty()) {
+ PinMuxManager::GetPinMuxManager()->ReleaseSource(bus_->mux,
+ bus_->mux_group);
+ }
+ bus_->driver_.reset();
+ }
+
+ bool WriteByte(uint8_t val) { return Transfer(&val, nullptr, sizeof(val)); }
+
+ bool WriteBuffer(const void* data, size_t len) {
+ return Transfer(data, nullptr, len);
+ }
+
+ bool Transfer(const void* tx_data, void* rx_data, size_t len) {
+ return bus_->driver_->Transfer(tx_data, rx_data, len);
+ }
+
+ bool SetFrequency(uint32_t speed_hz) {
+ return bus_->driver_->SetFrequency(speed_hz);
+ }
+
+ bool SetMode(int mode) { return bus_->driver_->SetMode(mode); }
+
+ bool SetBitJustification(bool lsb_first) {
+ return bus_->driver_->SetBitJustification(lsb_first);
+ }
+
+ bool SetBitsPerWord(uint32_t bits_per_word) {
+ return bus_->driver_->SetBitsPerWord(bits_per_word);
+ }
+
+ private:
+ SpiDevBus* bus_;
+};
+
+class SpiManager {
+ public:
+ friend class SpiManagerTest;
+ ~SpiManager();
+
+ // Get the singleton.
+ static SpiManager* GetSpiManager();
+
+ // Used by the BSP to tell PMan of an SPI bus
+ // that can be used by a PMan client.
+ // Will return false if the bus has already been registered.
+ bool RegisterSpiDevBus(const std::string& name, uint32_t bus, uint32_t cs);
+ std::vector<std::string> GetSpiDevBusses();
+
+ bool SetPinMux(const std::string& name, const std::string& mux);
+ bool SetPinMuxWithGroup(const std::string& name,
+ const std::string& mux,
+ const std::string& group);
+
+ bool RegisterDriver(std::unique_ptr<SpiDriverInfoBase> driver_info);
+
+ std::unique_ptr<SpiDevice> OpenSpiDevice(const std::string& name);
+
+ private:
+ SpiManager();
+
+ std::map<std::string, std::unique_ptr<SpiDriverInfoBase>> driver_infos_;
+ std::map<std::string, SpiDevBus> spidev_buses_;
+
+ DISALLOW_COPY_AND_ASSIGN(SpiManager);
+};
+
+} // namespace android
+
+#endif // SYSTEM_PERIPHERALMANAGER_DAEMON_SPI_MANAGER_H_
diff --git a/daemon/spi_manager_unittest.cc b/daemon/spi_manager_unittest.cc
new file mode 100644
index 0000000..51da825
--- /dev/null
+++ b/daemon/spi_manager_unittest.cc
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * 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.
+ */
+
+#include <stdio.h>
+
+#include <gtest/gtest.h>
+
+#include "fake_devices.h"
+#include "spi_manager.h"
+#include "spi_driver_spidev.h"
+
+namespace android {
+
+class FakeDeviceFactory : public CharDeviceFactory {
+ public:
+ FakeDeviceFactory() {}
+ ~FakeDeviceFactory(){};
+
+ std::unique_ptr<CharDeviceInterface> NewCharDevice() override {
+ return std::unique_ptr<CharDeviceInterface>(new FakeCharDevice());
+ }
+};
+
+class SpiManagerTest : public ::testing::Test {
+ public:
+ SpiManagerTest() {
+ manager.RegisterDriver(std::unique_ptr<SpiDriverInfoBase>(
+ new SpiDriverInfo<SpiDriverSpiDev, CharDeviceFactory*>(
+ &device_factory)));
+ }
+ ~SpiManagerTest() = default;
+
+ protected:
+ FakeDeviceFactory device_factory;
+ SpiManager manager;
+};
+
+TEST_F(SpiManagerTest, SimpleRegister) {
+ manager.RegisterSpiDevBus("SPI0_1", 0, 1);
+ std::vector<std::string> busses = manager.GetSpiDevBusses();
+ ASSERT_EQ(1U, busses.size());
+ ASSERT_EQ("SPI0_1", busses[0]);
+}
+
+TEST_F(SpiManagerTest, SimpleOpen) {
+ manager.RegisterSpiDevBus("SPI0_1", 0, 1);
+ std::unique_ptr<SpiDevice> device(manager.OpenSpiDevice("SPI0_1"));
+ ASSERT_NE(nullptr, device);
+ std::unique_ptr<SpiDevice> device2(manager.OpenSpiDevice("SPI0_1"));
+ ASSERT_EQ(nullptr, device2);
+ device.reset();
+ std::unique_ptr<SpiDevice> device3(manager.OpenSpiDevice("SPI0_1"));
+ ASSERT_NE(nullptr, device3);
+}
+
+TEST_F(SpiManagerTest, SetFrequency) {
+ manager.RegisterSpiDevBus("SPI0_1", 0, 1);
+ std::unique_ptr<SpiDevice> device(manager.OpenSpiDevice("SPI0_1"));
+ ASSERT_NE(nullptr, device);
+
+ device->SetFrequency(100);
+}
+
+} // namespace android \ No newline at end of file