diff options
author | Lee Campbell <leecam@google.com> | 2016-03-11 16:28:55 -0800 |
---|---|---|
committer | Lee Campbell <leecam@google.com> | 2016-03-15 15:11:22 -0700 |
commit | 99867e2357be2b06e676f43a32ece79e2e35581f (patch) | |
tree | daeec2b0901c8ba9e7b266f650ee3f5aa4195359 | |
parent | 8deeb0f6d253ec82c51c91c426d8f3c3a623d7c2 (diff) | |
download | peripheralmanager-99867e2357be2b06e676f43a32ece79e2e35581f.tar.gz |
Add I2C manager
Add basic support for I2C. Only Read Register
command supported so far.
BUG: 26776321
TEST: Testing I2C temp sensor
Change-Id: Id4a2e96df489c64b2724ac3995557459f285667c
-rw-r--r-- | client/Android.mk | 1 | ||||
-rw-r--r-- | client/i2c_device_impl.cc | 52 | ||||
-rw-r--r-- | client/i2c_device_impl.h | 42 | ||||
-rw-r--r-- | client/peripheral_manager_client_impl.cc | 11 | ||||
-rw-r--r-- | client/peripheral_manager_client_impl.h | 5 | ||||
-rw-r--r-- | client/wrapper.cc | 38 | ||||
-rw-r--r-- | daemon/Android.mk | 4 | ||||
-rw-r--r-- | daemon/i2c_driver.h | 71 | ||||
-rw-r--r-- | daemon/i2c_driver_i2cdev.cc | 111 | ||||
-rw-r--r-- | daemon/i2c_driver_i2cdev.h | 55 | ||||
-rw-r--r-- | daemon/i2c_manager.cc | 121 | ||||
-rw-r--r-- | daemon/i2c_manager.h | 101 | ||||
-rw-r--r-- | daemon/peripheral_manager.cc | 22 | ||||
-rw-r--r-- | daemon/peripheral_manager_client.cc | 56 | ||||
-rw-r--r-- | daemon/peripheral_manager_client.h | 19 | ||||
-rw-r--r-- | example/Android.mk | 16 | ||||
-rw-r--r-- | example/pio_mcp9808.cc | 62 | ||||
-rw-r--r-- | hal/hardware/peripheral_io.h | 4 | ||||
-rw-r--r-- | include/peripheralmanager/i2c_device.h | 54 | ||||
-rw-r--r-- | include/peripheralmanager/peripheral_manager_client.h | 22 | ||||
-rw-r--r-- | ipc/android/os/IPeripheralManagerClient.aidl | 8 |
21 files changed, 875 insertions, 0 deletions
diff --git a/client/Android.mk b/client/Android.mk index 6a98485..dc1ba38 100644 --- a/client/Android.mk +++ b/client/Android.mk @@ -42,6 +42,7 @@ LOCAL_SHARED_LIBRARIES := $(libperipheralman_CommonSharedLibraries) LOCAL_STATIC_LIBRARIES := libperipheralman_binder LOCAL_SRC_FILES := \ gpio_impl.cc \ + i2c_device_impl.cc \ led_impl.cc \ peripheral_manager_client_impl.cc \ spi_device_impl.cc \ diff --git a/client/i2c_device_impl.cc b/client/i2c_device_impl.cc new file mode 100644 index 0000000..841d1fd --- /dev/null +++ b/client/i2c_device_impl.cc @@ -0,0 +1,52 @@ +/* + * 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 <vector> + +#include <peripheralmanager/i2c_device.h> + +#include "i2c_device_impl.h" + +using android::sp; +using android::os::IPeripheralManagerClient; +using android::binder::Status; + +I2cDeviceImpl::I2cDeviceImpl(const std::string& name, + uint32_t address, + sp<IPeripheralManagerClient> client) + : name_(name), address_(address), client_(client) {} + +I2cDeviceImpl::~I2cDeviceImpl() { + client_->ReleaseI2cDevice(name_, address_); +} + +int I2cDeviceImpl::ReadRegByte(uint8_t reg, uint8_t* val) { + int32_t tmp_val; + int ret = client_->I2cReadRegByte(name_, address_, reg, &tmp_val).serviceSpecificErrorCode(); + if (!ret) { + *val = tmp_val; + } + return ret; +} + +int I2cDeviceImpl::ReadRegWord(uint8_t reg, uint16_t* val) { + int32_t tmp_val; + int ret = client_->I2cReadRegWord(name_, address_, reg, &tmp_val).serviceSpecificErrorCode(); + if (!ret) { + *val = tmp_val; + } + return ret; +}
\ No newline at end of file diff --git a/client/i2c_device_impl.h b/client/i2c_device_impl.h new file mode 100644 index 0000000..beff0c7 --- /dev/null +++ b/client/i2c_device_impl.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_I2C_DEVICE_IMPL_H_ +#define SYSTEM_PERIPHERALMANAGER_I2C_DEVICE_IMPL_H_ + +#include <string> + +#include <android/os/IPeripheralManagerClient.h> +#include <utils/StrongPointer.h> + +class I2cDeviceImpl { + public: + I2cDeviceImpl(const std::string& bus, + uint32_t address, + android::sp<android::os::IPeripheralManagerClient> client); + + int ReadRegByte(uint8_t reg, uint8_t* val); + int ReadRegWord(uint8_t reg, uint16_t* val); + + ~I2cDeviceImpl(); + + private: + std::string name_; + uint32_t address_; + android::sp<android::os::IPeripheralManagerClient> client_; +}; + +#endif // SYSTEM_PERIPHERALMANAGER_I2C_DEVICE_IMPL_H_
\ No newline at end of file diff --git a/client/peripheral_manager_client_impl.cc b/client/peripheral_manager_client_impl.cc index af44804..20b804c 100644 --- a/client/peripheral_manager_client_impl.cc +++ b/client/peripheral_manager_client_impl.cc @@ -71,3 +71,14 @@ int PeripheralManagerClientImpl::OpenLed(const std::string& name, } return status.serviceSpecificErrorCode(); } + +int PeripheralManagerClientImpl::OpenI2cDevice( + const std::string& name, + uint32_t address, + std::unique_ptr<I2cDeviceImpl>* device) { + Status status = client_->OpenI2cDevice(name, address); + if (status.isOk()) { + device->reset(new I2cDeviceImpl(name, address, client_)); + } + return status.serviceSpecificErrorCode(); +} diff --git a/client/peripheral_manager_client_impl.h b/client/peripheral_manager_client_impl.h index 80d3492..69f7b3b 100644 --- a/client/peripheral_manager_client_impl.h +++ b/client/peripheral_manager_client_impl.h @@ -21,6 +21,7 @@ #include <utils/StrongPointer.h> #include "gpio_impl.h" +#include "i2c_device_impl.h" #include "led_impl.h" #include "spi_device_impl.h" @@ -40,6 +41,10 @@ class PeripheralManagerClientImpl { int OpenLed(const std::string& name, std::unique_ptr<LedImpl>* device); int ListLeds(std::vector<std::string>* leds); + int OpenI2cDevice(const std::string& name, + uint32_t address, + std::unique_ptr<I2cDeviceImpl>* device); + private: android::sp<android::os::IPeripheralManagerClient> client_; android::sp<android::IBinder> lifeline_; diff --git a/client/wrapper.cc b/client/wrapper.cc index e7e800d..5ef1ffc 100644 --- a/client/wrapper.cc +++ b/client/wrapper.cc @@ -54,6 +54,10 @@ struct BLed { LedImpl* impl; }; +struct BI2cDevice { + I2cDeviceImpl* impl; +}; + BPeripheralManagerClient* BPeripheralManagerClient_new() { std::unique_ptr<PeripheralManagerClientImpl> impl( new PeripheralManagerClientImpl); @@ -69,6 +73,7 @@ void BPeripheralManagerClient_delete(BPeripheralManagerClient* client) { delete client; } +// GPIO API char** BPeripheralManagerClient_listGpio(const BPeripheralManagerClient* client, int* num_gpio) { std::vector<std::string> gpios; @@ -136,6 +141,7 @@ void BGpio_delete(BGpio* gpio) { delete gpio; } +// SPI API char** BPeripheralManagerClient_listSpiBuses( const BPeripheralManagerClient* client, int* num_spi_buses) { @@ -233,3 +239,35 @@ void BLed_delete(BLed* led) { delete led->impl; delete led; } + +// I2C API +int BPeripheralManagerClient_openI2cDevice( + const BPeripheralManagerClient* client, + const char* name, + uint32_t address, + BI2cDevice** dev) { + std::unique_ptr<I2cDeviceImpl> impl; + int ret = client->impl->OpenI2cDevice(name, address, &impl); + if (ret == 0) { + *dev = new BI2cDevice{impl.release()}; + } + + return ret; +} + +int BI2cDevice_readRegByte(const BI2cDevice* device, + uint8_t reg, + uint8_t* val) { + return device->impl->ReadRegByte(reg, val); +} + +int BI2cDevice_readRegWord(const BI2cDevice* device, + uint8_t reg, + uint16_t* val) { + return device->impl->ReadRegWord(reg, val); +} + +void BI2cDevice_delete(BI2cDevice* device) { + delete device->impl; + delete device; +} diff --git a/daemon/Android.mk b/daemon/Android.mk index 15bc1ef..caf1a3d 100644 --- a/daemon/Android.mk +++ b/daemon/Android.mk @@ -74,6 +74,8 @@ LOCAL_SRC_FILES := \ char_device.cc \ gpio_driver_sysfs.cc \ gpio_manager.cc \ + i2c_driver_i2cdev.cc \ + i2c_manager.cc \ led_driver_sysfs.cc \ led_manager.cc \ peripheral_manager.cc \ @@ -102,6 +104,8 @@ LOCAL_SRC_FILES := \ char_device.cc \ gpio_driver_sysfs.cc \ gpio_manager.cc \ + i2c_driver_i2cdev.cc \ + i2c_manager.cc \ led_driver_sysfs.cc \ led_manager.cc \ pin_mux_manager.cc \ diff --git a/daemon/i2c_driver.h b/daemon/i2c_driver.h new file mode 100644 index 0000000..dbb5c84 --- /dev/null +++ b/daemon/i2c_driver.h @@ -0,0 +1,71 @@ +/* + * 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_I2C_DRIVER_H_ +#define SYSTEM_PERIPHERALMANAGER_DAEMON_I2C_DRIVER_H_ + +#include <stdint.h> + +#include <memory> +#include <string> + +#include <base/macros.h> + +#include "peripheralmanager/constants.h" + +namespace android { + +class I2cDriverInterface { + public: + I2cDriverInterface() {} + virtual ~I2cDriverInterface() {} + + // TODO(leecam): Init should have generic params. + virtual bool Init(uint32_t bus_id, uint32_t address) = 0; + + virtual bool ReadRegByte(uint8_t reg, uint8_t* val) = 0; + virtual bool ReadRegWord(uint8_t reg, uint16_t* val) = 0; + +}; + +class I2cDriverInfoBase { + public: + I2cDriverInfoBase() {} + virtual ~I2cDriverInfoBase() {} + + virtual std::string Compat() = 0; + virtual std::unique_ptr<I2cDriverInterface> Probe() = 0; +}; + +template <class T, class PARAM> +class I2cDriverInfo : public I2cDriverInfoBase { + public: + I2cDriverInfo(PARAM param) : param_(param) {} + ~I2cDriverInfo() override {} + + std::string Compat() override { return T::Compat(); } + + std::unique_ptr<I2cDriverInterface> Probe() override { + return std::unique_ptr<I2cDriverInterface>(new T(param_)); + } + + private: + PARAM param_; +}; + +} // namespace android + +#endif // SYSTEM_PERIPHERALMANAGER_DAEMON_I2C_DRIVER_H_
\ No newline at end of file diff --git a/daemon/i2c_driver_i2cdev.cc b/daemon/i2c_driver_i2cdev.cc new file mode 100644 index 0000000..2dbc4c4 --- /dev/null +++ b/daemon/i2c_driver_i2cdev.cc @@ -0,0 +1,111 @@ +/* + * 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 "i2c_driver_i2cdev.h" + +#include <fcntl.h> +#include <linux/i2c.h> +#include <linux/i2c-dev.h> +#include <sys/ioctl.h> +#include <string> + +#include <base/logging.h> + +namespace android { +namespace { + +const char kI2cDevPath[] = "/dev/i2c-"; + +} // namespace + +I2cDriverI2cDev::I2cDriverI2cDev(CharDeviceFactory* char_device_factory) + : fd_(-1), char_device_factory_(char_device_factory) {} + +I2cDriverI2cDev::~I2cDriverI2cDev() { + if (fd_ >= 0 && char_interface_ != nullptr) { + char_interface_->Close(fd_); + } +} + +bool I2cDriverI2cDev::Init(uint32_t bus_id, uint32_t address) { + if (fd_ >= 0) { + return false; + } + // Get a char device. If char_device_factory_ is set + // then this is a unittest and the char device is provided + // by the test. Otherwise create a normal CharDevice. + if (!char_device_factory_) { + char_interface_.reset(new CharDevice()); + } else { + char_interface_ = char_device_factory_->NewCharDevice(); + } + + std::string path = kI2cDevPath + std::to_string(bus_id); + + int fd = char_interface_->Open(path.c_str(), O_RDWR); + if (fd < 0) + return false; + uintptr_t tmp_addr = address; + if (char_interface_->Ioctl(fd, I2C_SLAVE, (void*)tmp_addr) < 0) { + LOG(ERROR) << "Failed to set I2C slave"; + char_interface_->Close(fd); + return false; + } + + fd_ = fd; + + return true; +} + +bool I2cDriverI2cDev::ReadRegByte(uint8_t reg, uint8_t* val) { + union i2c_smbus_data data; + + struct i2c_smbus_ioctl_data smbus_args; + smbus_args.command = reg; + smbus_args.read_write = I2C_SMBUS_READ; + smbus_args.size = I2C_SMBUS_BYTE_DATA; + smbus_args.data = &data; + + if (char_interface_->Ioctl(fd_, I2C_SMBUS, &smbus_args) < 0) { + LOG(ERROR) << "Failed I2C_SMBUS"; + return false; + } + + *val = data.byte; + + return true; +} + +bool I2cDriverI2cDev::ReadRegWord(uint8_t reg, uint16_t* val) { + union i2c_smbus_data data; + + struct i2c_smbus_ioctl_data smbus_args; + smbus_args.command = reg; + smbus_args.read_write = I2C_SMBUS_READ; + smbus_args.size = I2C_SMBUS_WORD_DATA; + smbus_args.data = &data; + + if (char_interface_->Ioctl(fd_, I2C_SMBUS, &smbus_args) < 0) { + LOG(ERROR) << "Failed I2C_SMBUS"; + return false; + } + + *val = data.word; + + return true; +} + +} // namespace
\ No newline at end of file diff --git a/daemon/i2c_driver_i2cdev.h b/daemon/i2c_driver_i2cdev.h new file mode 100644 index 0000000..680494a --- /dev/null +++ b/daemon/i2c_driver_i2cdev.h @@ -0,0 +1,55 @@ +/* + * 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_I2C_DRIVER_I2CDEV_H_ +#define SYSTEM_PERIPHERALMANAGER_DAEMON_I2C_DRIVER_I2CDEV_H_ + +#include <stdint.h> + +#include <memory> + +#include <base/macros.h> + +#include "char_device.h" +#include "i2c_driver.h" + +namespace android { + +class I2cDriverI2cDev : public I2cDriverInterface { + public: + I2cDriverI2cDev(CharDeviceFactory* char_device_factory); + ~I2cDriverI2cDev(); + + static std::string Compat() { return "I2CDEV"; } + + bool Init(uint32_t bus_id, uint32_t address) override; + + bool ReadRegByte(uint8_t reg, uint8_t* val) override; + bool ReadRegWord(uint8_t reg, uint16_t* val) override; + + private: + int fd_; + + // Used for unit testing and is null in production. + // Ownership is in the test and outlives this class. + CharDeviceFactory* char_device_factory_; + std::unique_ptr<CharDeviceInterface> char_interface_; + DISALLOW_COPY_AND_ASSIGN(I2cDriverI2cDev); +}; + +} // namespace android + +#endif // SYSTEM_PERIPHERALMANAGER_DAEMON_I2C_DRIVER_I2CDEV_H_
\ No newline at end of file diff --git a/daemon/i2c_manager.cc b/daemon/i2c_manager.cc new file mode 100644 index 0000000..52035d1 --- /dev/null +++ b/daemon/i2c_manager.cc @@ -0,0 +1,121 @@ +/* + * 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 "i2c_manager.h" + +#include <base/logging.h> + +#include "pin_mux_manager.h" + +namespace android { + +std::unique_ptr<I2cManager> g_i2c_manager; + +I2cManager::I2cManager() {} + +I2cManager::~I2cManager() {} + +// static +I2cManager* I2cManager::GetI2cManager() { + if (!g_i2c_manager) { + g_i2c_manager.reset(new I2cManager()); + } + return g_i2c_manager.get(); +} + +bool I2cManager::RegisterI2cDevBus(const std::string& name, + uint32_t bus) { + if (i2cdev_buses_.count(name)) + return false; + i2cdev_buses_.emplace(name, I2cDevBus(bus)); + return true; +} + +std::vector<std::string> I2cManager::GetI2cDevBuses() { + std::vector<std::string> buses; + for (auto& i : i2cdev_buses_) + buses.push_back(i.first); + return buses; +} + +bool I2cManager::HasI2cDevBus(const std::string& name) { + return i2cdev_buses_.count(name); +} + +bool I2cManager::RegisterDriver( + std::unique_ptr<I2cDriverInfoBase> driver_info) { + std::string key = driver_info->Compat(); + driver_infos_[key] = std::move(driver_info); + return true; +} + +bool I2cManager::SetPinMux(const std::string& name, const std::string& mux) { + auto bus_it = i2cdev_buses_.find(name); + if (bus_it == i2cdev_buses_.end()) + return false; + bus_it->second.mux = mux; + bus_it->second.mux_group = mux; + return true; +} + +bool I2cManager::SetPinMuxWithGroup(const std::string& name, + const std::string& mux, + const std::string& group) { + auto bus_it = i2cdev_buses_.find(name); + if (bus_it == i2cdev_buses_.end()) + return false; + bus_it->second.mux = mux; + bus_it->second.mux_group = group; + return true; +} + +std::unique_ptr<I2cDevice> I2cManager::OpenI2cDevice(const std::string& name, uint32_t address) { + LOG(INFO) << "OpenI2cDevice " << name << " " << address; + // Get the Bus from the BSP. + auto bus_it = i2cdev_buses_.find(name); + if (bus_it == i2cdev_buses_.end()) + return nullptr; + + // Check its not already in use + if (bus_it->second.driver_.count(address)) { + return nullptr; + } + + // Find a driver. + // Currently there is only hardcoded support for I2CDEV + auto driver_info_it = driver_infos_.find("I2CDEV"); + + // Fail if there is no driver. + if (driver_info_it == driver_infos_.end()) + return nullptr; + + std::unique_ptr<I2cDriverInterface> driver(driver_info_it->second->Probe()); + + if (!driver->Init(bus_it->second.bus, address)) + 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_[address] = std::move(driver); + + return std::unique_ptr<I2cDevice>(new I2cDevice(&(bus_it->second), address)); +} + +} // namespace android diff --git a/daemon/i2c_manager.h b/daemon/i2c_manager.h new file mode 100644 index 0000000..46bee7e --- /dev/null +++ b/daemon/i2c_manager.h @@ -0,0 +1,101 @@ +/* + * 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_I2C_MANAGER_H_ +#define SYSTEM_PERIPHERALMANAGER_DAEMON_I2C_MANAGER_H_ + +#include <stdint.h> + +#include <map> +#include <memory> +#include <string> +#include <vector> + +#include <base/macros.h> + +#include "peripheralmanager/constants.h" +#include "pin_mux_manager.h" +#include "i2c_driver.h" + +namespace android { + +struct I2cDevBus { + I2cDevBus(uint32_t b) : bus(b) {} + uint32_t bus; + std::string mux; + std::string mux_group; + std::map<uint32_t, std::unique_ptr<I2cDriverInterface>> driver_; +}; + +class I2cDevice { + public: + I2cDevice(I2cDevBus* bus, uint32_t address) : bus_(bus), address_(address) {} + ~I2cDevice() { + if (!bus_->mux.empty()) { + PinMuxManager::GetPinMuxManager()->ReleaseSource(bus_->mux, + bus_->mux_group); + } + bus_->driver_.erase(address_); + } + + bool ReadRegByte(uint8_t reg, uint8_t* val) { + return bus_->driver_[address_]->ReadRegByte(reg, val); + } + + bool ReadRegWord(uint8_t reg, uint16_t* val) { + return bus_->driver_[address_]->ReadRegWord(reg, val); + } + + private: + I2cDevBus* bus_; + uint32_t address_; +}; + +class I2cManager { + public: + friend class I2cManagerTest; + ~I2cManager(); + + // Get the singleton. + static I2cManager* GetI2cManager(); + + bool RegisterI2cDevBus(const std::string& name, uint32_t bus); + + std::vector<std::string> GetI2cDevBuses(); + bool HasI2cDevBus(const std::string& name); + + 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<I2cDriverInfoBase> driver_info); + + std::unique_ptr<I2cDevice> OpenI2cDevice(const std::string& name, + uint32_t address); + + private: + I2cManager(); + + std::map<std::string, std::unique_ptr<I2cDriverInfoBase>> driver_infos_; + std::map<std::string, I2cDevBus> i2cdev_buses_; + + DISALLOW_COPY_AND_ASSIGN(I2cManager); +}; + +} // namespace android + +#endif // SYSTEM_PERIPHERALMANAGER_DAEMON_I2C_MANAGER_H_
\ No newline at end of file diff --git a/daemon/peripheral_manager.cc b/daemon/peripheral_manager.cc index 04915da..5d81b77 100644 --- a/daemon/peripheral_manager.cc +++ b/daemon/peripheral_manager.cc @@ -23,6 +23,8 @@ #include "gpio_driver_sysfs.h" #include "gpio_manager.h" +#include "i2c_driver_i2cdev.h" +#include "i2c_manager.h" #include "led_driver_sysfs.h" #include "led_manager.h" #include "pin_mux_manager.h" @@ -54,6 +56,15 @@ static int RegisterLedSysfs(const char* name, const char* sysfs_name) { return LedManager::GetLedManager()->RegisterLedSysfs(name, sysfs_name); } +// I2c callbacks +static int RegisterI2cDevBus(const char* name, uint32_t bus) { + return I2cManager::GetI2cManager()->RegisterI2cDevBus(name, bus); +} + +static int SetI2cPinMux(const char* name, const char* source) { + return I2cManager::GetI2cManager()->SetPinMux(name, source); +} + // Pin Mux callbacks. static int RegisterPin(const char* name, int gpio, @@ -127,6 +138,13 @@ bool PeripheralManager::RegisterDrivers() { LOG(ERROR) << "Failed to load driver: SpiDriverSpiDev"; return false; } + if (!I2cManager::GetI2cManager()->RegisterDriver( + std::unique_ptr<I2cDriverInfoBase>( + new I2cDriverInfo<I2cDriverI2cDev, CharDeviceFactory*>( + nullptr)))) { + LOG(ERROR) << "Failed to load driver: I2cDriverI2cDev"; + return false; + } if (!GpioManager::GetGpioManager()->RegisterDriver( std::unique_ptr<GpioDriverInfoBase>( new GpioDriverInfo<GpioDriverSysfs, void*>(nullptr)))) { @@ -164,6 +182,10 @@ bool PeripheralManager::InitHal() { // Led .register_led_sysfs = RegisterLedSysfs, + // I2c + .register_i2c_dev_bus = RegisterI2cDevBus, + .set_i2c_pin_mux = SetI2cPinMux, + // Pin Mux .register_pin = RegisterPin, .register_pin_group = RegisterPinGroup, diff --git a/daemon/peripheral_manager_client.cc b/daemon/peripheral_manager_client.cc index 128700b..051f2fb 100644 --- a/daemon/peripheral_manager_client.cc +++ b/daemon/peripheral_manager_client.cc @@ -298,4 +298,60 @@ Status PeripheralManagerClient::LedSetBrightness(const std::string& name, return Status::fromServiceSpecificError(EREMOTEIO); } +Status PeripheralManagerClient::OpenI2cDevice(const std::string& name, + int32_t address) { + if (!I2cManager::GetI2cManager()->HasI2cDevBus(name)) + return Status::fromServiceSpecificError(ENODEV); + + std::unique_ptr<I2cDevice> device = + I2cManager::GetI2cManager()->OpenI2cDevice(name, address); + + if (!device) { + LOG(ERROR) << "Failed to open device " << name; + return Status::fromServiceSpecificError(EBUSY); + } + std::pair<std::string, uint32_t> i2c_dev(name, address); + i2c_devices_.emplace(i2c_dev, std::move(device)); + return Status::ok(); +} + +Status PeripheralManagerClient::ReleaseI2cDevice(const std::string& name, + int32_t address) { + if (!i2c_devices_.count({name, address})) + return Status::fromServiceSpecificError(EPERM); + + i2c_devices_.erase({name, address}); + return Status::ok(); +} + +Status PeripheralManagerClient::I2cReadRegByte(const std::string& name, + int32_t address, + int32_t reg, + int32_t* val) { + if (!i2c_devices_.count({name, address})) + return Status::fromServiceSpecificError(EPERM); + uint8_t tmp_val = 0; + if (i2c_devices_.find({name, address})->second->ReadRegByte(reg, &tmp_val)) { + *val = tmp_val; + return Status::ok(); + } + + return Status::fromServiceSpecificError(EREMOTEIO); +} + +Status PeripheralManagerClient::I2cReadRegWord(const std::string& name, + int32_t address, + int32_t reg, + int32_t* val) { + if (!i2c_devices_.count({name, address})) + return Status::fromServiceSpecificError(EPERM); + uint16_t tmp_val = 0; + if (i2c_devices_.find({name, address})->second->ReadRegWord(reg, &tmp_val)) { + *val = tmp_val; + return Status::ok(); + } + + return Status::fromServiceSpecificError(EREMOTEIO); +} + } // namespace android diff --git a/daemon/peripheral_manager_client.h b/daemon/peripheral_manager_client.h index 8b15618..ab7ded5 100644 --- a/daemon/peripheral_manager_client.h +++ b/daemon/peripheral_manager_client.h @@ -26,6 +26,7 @@ #include <android/os/BnPeripheralManagerClient.h> #include "gpio_manager.h" +#include "i2c_manager.h" #include "led_manager.h" #include "spi_manager.h" @@ -104,8 +105,26 @@ class PeripheralManagerClient : public BnPeripheralManagerClient { virtual Status LedSetBrightness(const std::string& name, int brightness) override; + virtual Status OpenI2cDevice(const std::string& name, + int32_t address) override; + + virtual Status ReleaseI2cDevice(const std::string& name, + int32_t address) override; + + virtual Status I2cReadRegByte(const std::string& name, + int32_t address, + int32_t reg, + int32_t* val) override; + + virtual Status I2cReadRegWord(const std::string& name, + int32_t address, + int32_t reg, + int32_t* val) override; + private: std::map<std::string, std::unique_ptr<GpioPin>> gpios_; + std::map<std::pair<std::string, uint32_t>, std::unique_ptr<I2cDevice>> + i2c_devices_; std::map<std::string, std::unique_ptr<SpiDevice>> spi_devices_; std::map<std::string, std::unique_ptr<Led>> leds_; DISALLOW_COPY_AND_ASSIGN(PeripheralManagerClient); diff --git a/example/Android.mk b/example/Android.mk index eb9b3f5..383b987 100644 --- a/example/Android.mk +++ b/example/Android.mk @@ -85,3 +85,19 @@ LOCAL_SRC_FILES := \ led_example.cc \ include $(BUILD_EXECUTABLE) + +include $(CLEAR_VARS) +LOCAL_MODULE := pio_mcp9808 +LOCAL_CPP_EXTENSION := .cc +LOCAL_CFLAGS := -Wall -Werror -Wno-unused-parameter +LOCAL_CFLAGS += -Wno-sign-promo # for libchrome +LOCAL_SHARED_LIBRARIES := \ + libbrillo \ + libchrome \ + libperipheralman \ + libutils \ + +LOCAL_SRC_FILES := \ + pio_mcp9808.cc \ + +include $(BUILD_EXECUTABLE) diff --git a/example/pio_mcp9808.cc b/example/pio_mcp9808.cc new file mode 100644 index 0000000..446afbf --- /dev/null +++ b/example/pio_mcp9808.cc @@ -0,0 +1,62 @@ +/* + * 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 <arpa/inet.h> +#include <unistd.h> + +#include <memory> + +#include <base/logging.h> +#include <brillo/flag_helper.h> + +#include <peripheralmanager/peripheral_manager_client.h> + +int main(int argc, char* argv[]) { + brillo::FlagHelper::Init(argc, argv, "PeripheralManager client."); + logging::InitLogging(logging::LoggingSettings()); + + // Get a client to the PeripheralManager. + BPeripheralManagerClient* client = BPeripheralManagerClient_new(); + + if (!client) { + LOG(ERROR) << "Failed to connect to client"; + return 1; + } + + // Open I2C bus. + BI2cDevice* i2c_device; + int ret = + BPeripheralManagerClient_openI2cDevice(client, "I2C6", 0x18, &i2c_device); + if (ret) { + LOG(ERROR) << "Failed to open I2C: " << strerror(ret); + return 1; + } + + uint16_t val = 0; + BI2cDevice_readRegWord(i2c_device, 0x05, &val); + + val = ntohs(val); + float temp = (val >> 4) & 0xFF; + temp += (float)(val & 0xF) / 16; + printf("Temp: %f\n", temp); + + BI2cDevice_delete(i2c_device); + + // Close the connection to PeripheralManager. + BPeripheralManagerClient_delete(client); + + return 0; +} diff --git a/hal/hardware/peripheral_io.h b/hal/hardware/peripheral_io.h index ae2aa26..a68beac 100644 --- a/hal/hardware/peripheral_io.h +++ b/hal/hardware/peripheral_io.h @@ -67,6 +67,10 @@ typedef struct peripheral_registration_cb_t { // Led functions int (*register_led_sysfs)(const char* name, const char* sysfs_name); + // I2c functions. + int (*register_i2c_dev_bus)(const char* name, uint32_t bus); + int (*set_i2c_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/i2c_device.h b/include/peripheralmanager/i2c_device.h new file mode 100644 index 0000000..f55de01 --- /dev/null +++ b/include/peripheralmanager/i2c_device.h @@ -0,0 +1,54 @@ +/* + * 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_I2C_DEVICE_H_ +#define SYSTEM_PERIPHERALMANAGER_I2C_DEVICE_H_ + +#include <sys/cdefs.h> +#include <sys/types.h> + +__BEGIN_DECLS + +/// @defgroup I2c I2c device interface +/// @brief Functions to control an I2C device. +/// +/// These functions can be used to control an I2C device. +/// @{ + +typedef struct BI2cDevice BI2cDevice; + + +/// Reads an I2C register. +/// @param device Pointer to the BI2cDevice struct. +/// @param val Output pointer to value to read. +/// @return 0 on success, errno on error +int BI2cDevice_readRegByte(const BI2cDevice* device, uint8_t reg, uint8_t* val); + +/// Reads an I2C register. +/// @param device Pointer to the BI2cDevice struct. +/// @param val Output pointer to value to read. +/// @return 0 on success, errno on error +int BI2cDevice_readRegWord(const BI2cDevice* device, uint8_t reg, uint16_t* val); + +/// Destroys a BI2cDevice struct. +/// @param device Pointer to the BI2cDevice struct. +void BI2cDevice_delete(BI2cDevice* device); + +/// @} + +__END_DECLS + +#endif // SYSTEM_PERIPHERALMANAGER_I2C_DEVICE_H_ diff --git a/include/peripheralmanager/peripheral_manager_client.h b/include/peripheralmanager/peripheral_manager_client.h index bb76099..8941a4c 100644 --- a/include/peripheralmanager/peripheral_manager_client.h +++ b/include/peripheralmanager/peripheral_manager_client.h @@ -20,6 +20,7 @@ #include <sys/cdefs.h> #include "peripheralmanager/gpio.h" +#include "peripheralmanager/i2c_device.h" #include "peripheralmanager/led.h" #include "peripheralmanager/spi_device.h" @@ -94,6 +95,27 @@ int BPeripheralManagerClient_openLed(const BPeripheralManagerClient* client, const char* name, BLed** led); +/// Returns the list of I2C buses. +/// This does not take ownership into account. +/// The list must be freed by the caller. +/// @param client Pointer to the BPeripheralManagerClient struct. +/// @param num_i2c_buses Output pointer to the number of element in the list. +/// @return The list of i2c buses. +char** BPeripheralManagerClient_listI2cBuses( + const BPeripheralManagerClient* client, + int* num_i2c_buses); + +/// Opens an I2C device and takes ownership of it. +/// @oaram client Pointer to the BPeripheralManagerClient struct. +/// @param name Name of the SPI device. +/// @param dev Output pointer to the BI2cDevice struct. Empty on error. +/// @return 0 on success, errno on error +int BPeripheralManagerClient_openI2cDevice( + const BPeripheralManagerClient* client, + const char* name, + uint32_t address, + BI2cDevice** dev); + /// Creates a new client. /// @return A pointer to the created client. nullptr on errors. BPeripheralManagerClient* BPeripheralManagerClient_new(); diff --git a/ipc/android/os/IPeripheralManagerClient.aidl b/ipc/android/os/IPeripheralManagerClient.aidl index 978057e..0fb3561 100644 --- a/ipc/android/os/IPeripheralManagerClient.aidl +++ b/ipc/android/os/IPeripheralManagerClient.aidl @@ -68,4 +68,12 @@ interface IPeripheralManagerClient { int LedGetMaxBrightness(@utf8InCpp String name); void LedSetBrightness(@utf8InCpp String name, int brightness); + + void OpenI2cDevice(@utf8InCpp String name, int address); + + void ReleaseI2cDevice(@utf8InCpp String name, int address); + + int I2cReadRegByte(@utf8InCpp String name, int address, int reg); + + int I2cReadRegWord(@utf8InCpp String name, int address, int reg); } |