diff options
author | Lee Campbell <leecam@google.com> | 2016-03-08 16:00:55 -0800 |
---|---|---|
committer | Lee Campbell <leecam@google.com> | 2016-03-08 17:07:56 -0800 |
commit | c589f9dc35abbd00601d50f732a4d7e0c83dccc1 (patch) | |
tree | 1a5d47d9d03b6ca294bc0258291dc17c6edf77a8 | |
parent | e1adeba7ee43e6c609655c764d5dc8a7748d0126 (diff) | |
download | peripheralmanager-c589f9dc35abbd00601d50f732a4d7e0c83dccc1.tar.gz |
Hook up the SPI HAL to the SPI manager
Implement the backend IOCTLS for SPI
BUG: 27555414
Change-Id: I4be6b9e33dd7b6d2483a04f368289a3229df0439
TEST: Tested with an RGB led
-rw-r--r-- | client/wrapper.cc | 2 | ||||
-rw-r--r-- | daemon/peripheral_manager.cc | 40 | ||||
-rw-r--r-- | daemon/spi_driver.h | 2 | ||||
-rw-r--r-- | daemon/spi_driver_spidev.cc | 72 | ||||
-rw-r--r-- | daemon/spi_driver_spidev.h | 4 | ||||
-rw-r--r-- | daemon/spi_manager.h | 2 | ||||
-rw-r--r-- | example/Android.mk | 18 | ||||
-rw-r--r-- | example/pio_flash_apa10c.cc | 82 | ||||
-rw-r--r-- | hal/hardware/peripheral_io.h | 6 | ||||
-rw-r--r-- | include/peripheralmanager/spi_device.h | 2 |
10 files changed, 214 insertions, 16 deletions
diff --git a/client/wrapper.cc b/client/wrapper.cc index 03f7e02..1ac11d4 100644 --- a/client/wrapper.cc +++ b/client/wrapper.cc @@ -144,7 +144,7 @@ int BSpiDevice_setBitJustification(const BSpiDevice* device, } int BSpiDevice_setBitsPerWord(const BSpiDevice* device, - uint32_t bits_per_word) { + uint8_t bits_per_word) { return device->impl->SetBitsPerWord(bits_per_word); } diff --git a/daemon/peripheral_manager.cc b/daemon/peripheral_manager.cc index 0ab602d..2a1e038 100644 --- a/daemon/peripheral_manager.cc +++ b/daemon/peripheral_manager.cc @@ -24,6 +24,7 @@ #include "gpio_driver_sysfs.h" #include "gpio_manager.h" #include "pin_mux_manager.h" +#include "spi_driver_spidev.h" namespace android { namespace { @@ -37,6 +38,15 @@ static int SetGpioPinMux(const char* name, const char* source) { return GpioManager::GetGpioManager()->SetPinMux(name, source); } +// Spi callbacks +static int RegisterSpiDevBus(const char* name, uint32_t bus, uint32_t cs) { + return SpiManager::GetSpiManager()->RegisterSpiDevBus(name, bus, cs); +} + +static int SetSpiPinMux(const char* name, const char* source) { + return SpiManager::GetSpiManager()->SetPinMux(name, source); +} + // Pin Mux callbacks. static int RegisterPin(const char* name, int gpio, @@ -58,7 +68,9 @@ static int RegisterSource(const char* name, char** groups, size_t nr_groups) { return PinMuxManager::GetPinMuxManager()->RegisterSource(name, groups_set); } -static int RegisterSimpleSource(const char* name, char** pins, size_t nr_pins) { +static int RegisterSimpleSource(const char* name, + const char** pins, + size_t nr_pins) { std::set<std::string> pins_set; for (size_t i = 0; i < nr_pins; i++) pins_set.emplace(pins[i]); @@ -73,7 +85,7 @@ PeripheralManager::PeripheralManager() {} PeripheralManager::~PeripheralManager() = default; bool PeripheralManager::Init() { - if(!RegisterDrivers()) + if (!RegisterDrivers()) return false; if (!InitHal()) @@ -101,10 +113,20 @@ void PeripheralManager::binderDied(const wp<IBinder>& who) { } bool PeripheralManager::RegisterDrivers() { - // Register GPIO Sysfs driver. - return GpioManager::GetGpioManager()->RegisterDriver( - std::unique_ptr<GpioDriverInfoBase>( - new GpioDriverInfo<GpioDriverSysfs, void*>(nullptr))); + if (!SpiManager::GetSpiManager()->RegisterDriver( + std::unique_ptr<SpiDriverInfoBase>( + new SpiDriverInfo<SpiDriverSpiDev, CharDeviceFactory*>( + nullptr)))) { + LOG(ERROR) << "Failed to load driver: SpiDriverSpiDev"; + return false; + } + if (!GpioManager::GetGpioManager()->RegisterDriver( + std::unique_ptr<GpioDriverInfoBase>( + new GpioDriverInfo<GpioDriverSysfs, void*>(nullptr)))) { + LOG(ERROR) << "Failed to load driver: GpioDriverSysfs"; + return false; + } + return true; } bool PeripheralManager::InitHal() { @@ -118,9 +140,15 @@ bool PeripheralManager::InitHal() { reinterpret_cast<const peripheral_io_module_t*>(module); struct peripheral_registration_cb_t callbacks = { + // Gpio .register_gpio_sysfs = RegisterGpioSysfs, .set_gpio_pin_mux = SetGpioPinMux, + // Spi + .register_spi_dev_bus = RegisterSpiDevBus, + .set_spi_pin_mux = SetSpiPinMux, + + // Pin Mux .register_pin = RegisterPin, .register_pin_group = RegisterPinGroup, .register_source = RegisterSource, diff --git a/daemon/spi_driver.h b/daemon/spi_driver.h index 9894886..3f04e36 100644 --- a/daemon/spi_driver.h +++ b/daemon/spi_driver.h @@ -39,7 +39,7 @@ class SpiDriverInterface { virtual bool SetFrequency(uint32_t speed_hz) = 0; virtual bool SetMode(SpiMode mode) = 0; virtual bool SetBitJustification(bool lsb_first) = 0; - virtual bool SetBitsPerWord(uint32_t bits_per_word) = 0; + virtual bool SetBitsPerWord(uint8_t bits_per_word) = 0; }; class SpiDriverInfoBase { diff --git a/daemon/spi_driver_spidev.cc b/daemon/spi_driver_spidev.cc index 7870b84..55bb630 100644 --- a/daemon/spi_driver_spidev.cc +++ b/daemon/spi_driver_spidev.cc @@ -61,12 +61,37 @@ bool SpiDriverSpiDev::Init(uint32_t bus_id, uint32_t cs) { return false; fd_ = fd; + + // Set the default speed to the max + uint32_t max_freq = 0; + if (!GetMaxFrequency(&max_freq)) { + char_interface_->Close(fd_); + fd_ = -1; + return false; + } + speed_hz_ = max_freq; + + // Default to 8 bits per word. + bits_per_word_ = 8; + return true; } -// TODO(leecam): Wire up these IOCTLs once the client code lands. bool SpiDriverSpiDev::Transfer(const void* tx_data, void* rx_data, size_t len) { - LOG(INFO) << "SPI Transfer"; + struct spi_ioc_transfer msg; + memset(&msg, 0, sizeof(msg)); + + msg.tx_buf = (unsigned long)tx_data; + msg.rx_buf = (unsigned long)rx_data; + msg.speed_hz = speed_hz_; + msg.bits_per_word = bits_per_word_; + msg.delay_usecs = 0; + msg.len = len; + + if (char_interface_->Ioctl(fd_, SPI_IOC_MESSAGE(1), &msg) < 0) { + PLOG(ERROR) << "SPI Transfer IOCTL Failed"; + return false; + } return true; } @@ -75,7 +100,7 @@ bool SpiDriverSpiDev::SetFrequency(uint32_t speed_hz) { return false; // Get the max speed and ensure speed_hz is less than it. uint32_t max_speed = 0; - if (char_interface_->Ioctl(fd_, SPI_IOC_RD_MAX_SPEED_HZ, &max_speed) != 0) + if (!GetMaxFrequency(&max_speed)) return false; if (speed_hz > max_speed) speed_hz = max_speed; @@ -84,15 +109,54 @@ bool SpiDriverSpiDev::SetFrequency(uint32_t speed_hz) { return true; } +bool SpiDriverSpiDev::GetMaxFrequency(uint32_t* max_freq) { + if (char_interface_->Ioctl(fd_, SPI_IOC_RD_MAX_SPEED_HZ, max_freq) < 0) { + PLOG(ERROR) << "Failed to get spi max freq"; + return false; + } + return true; +} + bool SpiDriverSpiDev::SetMode(SpiMode mode) { + uint8_t k_mode = 0; + switch (mode) { + case kMode0: + k_mode = SPI_MODE_0; + break; + case kMode1: + k_mode = SPI_MODE_1; + break; + case kMode2: + k_mode = SPI_MODE_2; + break; + case kMode3: + k_mode = SPI_MODE_3; + break; + } + + if (ioctl(fd_, SPI_IOC_WR_MODE, &k_mode) < 0) { + PLOG(ERROR) << "Failed to set mode"; + return false; + } + return true; } bool SpiDriverSpiDev::SetBitJustification(bool lsb_first) { + uint8_t k_lsb_first = lsb_first; + if (ioctl(fd_, SPI_IOC_WR_LSB_FIRST, &k_lsb_first) < 0) { + PLOG(ERROR) << "Failed to set bit justifcation"; + return false; + } return true; } -bool SpiDriverSpiDev::SetBitsPerWord(uint32_t bits_per_word) { +bool SpiDriverSpiDev::SetBitsPerWord(uint8_t bits_per_word) { + if (ioctl(fd_, SPI_IOC_WR_BITS_PER_WORD, &bits_per_word) < 0) { + PLOG(ERROR) << "Failed to set bits per word"; + return false; + } + bits_per_word_ = bits_per_word; return true; } diff --git a/daemon/spi_driver_spidev.h b/daemon/spi_driver_spidev.h index 6dfc0d1..1214e2b 100644 --- a/daemon/spi_driver_spidev.h +++ b/daemon/spi_driver_spidev.h @@ -40,9 +40,11 @@ class SpiDriverSpiDev : public SpiDriverInterface { bool SetFrequency(uint32_t speed_hz) override; bool SetMode(SpiMode mode) override; bool SetBitJustification(bool lsb_first) override; - bool SetBitsPerWord(uint32_t bits_per_word) override; + bool SetBitsPerWord(uint8_t bits_per_word) override; private: + bool GetMaxFrequency(uint32_t* max_freq); + int fd_; uint32_t bits_per_word_; uint32_t speed_hz_; diff --git a/daemon/spi_manager.h b/daemon/spi_manager.h index 6c3c3fb..92fc9ac 100644 --- a/daemon/spi_manager.h +++ b/daemon/spi_manager.h @@ -72,7 +72,7 @@ class SpiDevice { return bus_->driver_->SetBitJustification(lsb_first); } - bool SetBitsPerWord(uint32_t bits_per_word) { + bool SetBitsPerWord(uint8_t bits_per_word) { return bus_->driver_->SetBitsPerWord(bits_per_word); } diff --git a/example/Android.mk b/example/Android.mk index 82a1a6e..c3e1ddd 100644 --- a/example/Android.mk +++ b/example/Android.mk @@ -36,3 +36,21 @@ LOCAL_SRC_FILES := \ peripheralmanager_example.cc \ include $(BUILD_EXECUTABLE) + +include $(CLEAR_VARS) +LOCAL_MODULE := pio_flash_apa10c +LOCAL_CPP_EXTENSION := .cc +LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter +LOCAL_CFLAGS += -Wno-sign-promo # for libchrome +LOCAL_SHARED_LIBRARIES := \ + libbinder \ + libbinderwrapper \ + libbrillo \ + libchrome \ + libperipheralman \ + libutils \ + +LOCAL_SRC_FILES := \ + pio_flash_apa10c.cc \ + +include $(BUILD_EXECUTABLE) diff --git a/example/pio_flash_apa10c.cc b/example/pio_flash_apa10c.cc new file mode 100644 index 0000000..68abc49 --- /dev/null +++ b/example/pio_flash_apa10c.cc @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2015 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 <unistd.h> + +#include <memory> + +#include <base/at_exit.h> +#include <base/logging.h> +#include <base/message_loop/message_loop.h> +#include <base/sys_info.h> +#include <base/time/time.h> +#include <binderwrapper/binder_wrapper.h> +#include <brillo/flag_helper.h> + +#include <peripheralmanager/peripheral_manager_client.h> + +void SetLed(const BSpiDevice* my_spi, uint8_t r, uint8_t g, uint8_t b) { + uint8_t start_frame[] = {0x00, 0x00, 0x00, 0x00}; + uint8_t on_frame[4] = {0xff, 0x00, 0x00, 0x00}; + uint8_t end_frame[] = {0xff, 0xff, 0xff, 0xff}; + on_frame[1] = b; + on_frame[2] = g; + on_frame[3] = r; + BSpiDevice_writeBuffer(my_spi, start_frame, sizeof(start_frame)); + BSpiDevice_writeBuffer(my_spi, on_frame, sizeof(on_frame)); + BSpiDevice_writeBuffer(my_spi, end_frame, sizeof(end_frame)); +} + +int main(int argc, char* argv[]) { + brillo::FlagHelper::Init(argc, argv, "PeripheralManager client."); + logging::InitLogging(logging::LoggingSettings()); + android::BinderWrapper::Create(); + + LOG(INFO) << "PeripheralManager Client"; + + // Get a client to the PeripheralManager. + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + + if (!client) { + LOG(ERROR) << "Failed to connect to client"; + return 1; + } + + // Open SPI bus. + BSpiDevice* my_spi; + if (BPeripheralManagerClient_openSpiDevice(client, "SPI2", &my_spi) != + PERIPHERAL_IO_OK) { + LOG(ERROR) << "Failed to open Spi"; + return 1; + } + + BSpiDevice_setFrequency(my_spi, 400000); + + SetLed(my_spi, 0xff, 0x0, 0x0); + sleep(1); + SetLed(my_spi, 0x00, 0xff, 0x0); + sleep(1); + SetLed(my_spi, 0x00, 0x0, 0xff); + sleep(1); + + BSpiDevice_delete(my_spi); + + // Close the connection to PeripheralManager. + BPeripheralManagerClient_delete(client); + + LOG(INFO) << "Exiting"; + return 0; +} diff --git a/hal/hardware/peripheral_io.h b/hal/hardware/peripheral_io.h index d08898b..1aa44d5 100644 --- a/hal/hardware/peripheral_io.h +++ b/hal/hardware/peripheral_io.h @@ -54,12 +54,16 @@ typedef struct peripheral_registration_cb_t { int (*register_pin)(const char* name, int gpio, pin_mux_callbacks callbacks); int (*register_pin_group)(const char* name, char** pins, size_t nr_pins); int (*register_source)(const char* name, char** groups, size_t nr_groups); - int (*register_simple_source)(const char* name, char** pins, size_t nr_pins); + int (*register_simple_source)(const char* name, const char** pins, size_t nr_pins); // Gpio functions. int (*register_gpio_sysfs)(const char* name, uint32_t index); int (*set_gpio_pin_mux)(const char* name, const char* source); + // Spi functions. + int (*register_spi_dev_bus)(const char* name, uint32_t bus, uint32_t cs); + int (*set_spi_pin_mux)(const char* name, const char* source); + } peripheral_registration_cb_t; typedef struct peripheral_io_module_t peripheral_io_module_t; diff --git a/include/peripheralmanager/spi_device.h b/include/peripheralmanager/spi_device.h index 3c65d28..631dae6 100644 --- a/include/peripheralmanager/spi_device.h +++ b/include/peripheralmanager/spi_device.h @@ -99,7 +99,7 @@ int BSpiDevice_setBitJustification(const BSpiDevice* device, /// @param device Pointer to the BSpiDevice struct. /// @param bits_per_word Number of bits per word. /// @return Error code. -int BSpiDevice_setBitsPerWord(const BSpiDevice* device, uint32_t bits_per_word); +int BSpiDevice_setBitsPerWord(const BSpiDevice* device, uint8_t bits_per_word); /// Destroys a BSpiDevice struct. /// @param device Pointer to the BSpiDevice struct. |