aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLee Campbell <leecam@google.com>2016-03-11 16:28:55 -0800
committerLee Campbell <leecam@google.com>2016-03-15 15:11:22 -0700
commit99867e2357be2b06e676f43a32ece79e2e35581f (patch)
treedaeec2b0901c8ba9e7b266f650ee3f5aa4195359
parent8deeb0f6d253ec82c51c91c426d8f3c3a623d7c2 (diff)
downloadperipheralmanager-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.mk1
-rw-r--r--client/i2c_device_impl.cc52
-rw-r--r--client/i2c_device_impl.h42
-rw-r--r--client/peripheral_manager_client_impl.cc11
-rw-r--r--client/peripheral_manager_client_impl.h5
-rw-r--r--client/wrapper.cc38
-rw-r--r--daemon/Android.mk4
-rw-r--r--daemon/i2c_driver.h71
-rw-r--r--daemon/i2c_driver_i2cdev.cc111
-rw-r--r--daemon/i2c_driver_i2cdev.h55
-rw-r--r--daemon/i2c_manager.cc121
-rw-r--r--daemon/i2c_manager.h101
-rw-r--r--daemon/peripheral_manager.cc22
-rw-r--r--daemon/peripheral_manager_client.cc56
-rw-r--r--daemon/peripheral_manager_client.h19
-rw-r--r--example/Android.mk16
-rw-r--r--example/pio_mcp9808.cc62
-rw-r--r--hal/hardware/peripheral_io.h4
-rw-r--r--include/peripheralmanager/i2c_device.h54
-rw-r--r--include/peripheralmanager/peripheral_manager_client.h22
-rw-r--r--ipc/android/os/IPeripheralManagerClient.aidl8
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);
}