summaryrefslogtreecommitdiff
path: root/firmware/os/drivers/hall_twopole/hall_twopole.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/os/drivers/hall_twopole/hall_twopole.c')
-rw-r--r--firmware/os/drivers/hall_twopole/hall_twopole.c250
1 files changed, 250 insertions, 0 deletions
diff --git a/firmware/os/drivers/hall_twopole/hall_twopole.c b/firmware/os/drivers/hall_twopole/hall_twopole.c
new file mode 100644
index 00000000..847071f2
--- /dev/null
+++ b/firmware/os/drivers/hall_twopole/hall_twopole.c
@@ -0,0 +1,250 @@
+/*
+ * 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 <stdlib.h>
+#include <string.h>
+#include <float.h>
+
+#include <eventnums.h>
+#include <gpio.h>
+#include <heap.h>
+#include <hostIntf.h>
+#include <isr.h>
+#include <nanohubPacket.h>
+#include <sensors.h>
+#include <seos.h>
+#include <timer.h>
+#include <plat/gpio.h>
+#include <plat/exti.h>
+#include <plat/syscfg.h>
+#include <variant/variant.h>
+
+#define APP_ID APP_ID_MAKE(APP_ID_VENDOR_GOOGLE, 11)
+#define APP_VERSION 2
+
+#define HALL_REPORT_OPENED_VALUE 0
+#define HALL_REPORT_CLOSED_VALUE 1
+#define HALL_DEBOUNCE_TIMER_DELAY 10000000ULL // 10 milliseconds
+
+#ifndef HALL_S_PIN
+#error "HALL_S_PIN is not defined; please define in variant.h"
+#endif
+#ifndef HALL_S_IRQ
+#error "HALL_S_IRQ is not defined; please define in variant.h"
+#endif
+#ifndef HALL_N_PIN
+#error "HALL_N_PIN is not defined; please define in variant.h"
+#endif
+#ifndef HALL_N_IRQ
+#error "HALL_N_IRQ is not defined; please define in variant.h"
+#endif
+
+#define MAKE_TYPE(sPin,nPin) (sPin ? HALL_REPORT_OPENED_VALUE : HALL_REPORT_CLOSED_VALUE) + \
+ ((nPin ? HALL_REPORT_OPENED_VALUE : HALL_REPORT_CLOSED_VALUE) << 1)
+
+static struct SensorTask
+{
+ struct Gpio *sPin;
+ struct Gpio *nPin;
+ struct ChainedIsr sIsr;
+ struct ChainedIsr nIsr;
+
+ uint32_t id;
+ uint32_t sensorHandle;
+ uint32_t debounceTimerHandle;
+
+ int32_t prevReportedState;
+
+ bool on;
+} mTask;
+
+static void hallReportState(int32_t pinState)
+{
+ union EmbeddedDataPoint sample;
+ if (pinState != mTask.prevReportedState) {
+ mTask.prevReportedState = pinState;
+ sample.idata = pinState;
+ osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_HALL), sample.vptr, NULL);
+ }
+}
+
+static void debounceTimerCallback(uint32_t timerId, void *cookie)
+{
+ int32_t prevPinState = (int32_t)cookie;
+ int32_t currPinState = MAKE_TYPE(gpioGet(mTask.sPin), gpioGet(mTask.nPin));
+
+ if (mTask.on && (currPinState == prevPinState)) {
+ hallReportState(currPinState);
+ }
+}
+
+static void startDebounceTimer(struct SensorTask *data)
+{
+ int32_t currPinState = MAKE_TYPE(gpioGet(data->sPin), gpioGet(data->nPin));
+ if (data->debounceTimerHandle)
+ timTimerCancel(data->debounceTimerHandle);
+
+ data->debounceTimerHandle = timTimerSet(HALL_DEBOUNCE_TIMER_DELAY, 0, 50, debounceTimerCallback, (void*)currPinState, true /* oneShot */);
+}
+
+static bool hallSouthIsr(struct ChainedIsr *localIsr)
+{
+ struct SensorTask *data = container_of(localIsr, struct SensorTask, sIsr);
+ if (data->on)
+ startDebounceTimer(data);
+ extiClearPendingGpio(data->sPin);
+ return true;
+}
+
+static bool hallNorthIsr(struct ChainedIsr *localIsr)
+{
+ struct SensorTask *data = container_of(localIsr, struct SensorTask, nIsr);
+ if (data->on)
+ startDebounceTimer(data);
+ extiClearPendingGpio(data->nPin);
+ return true;
+}
+
+static bool enableInterrupt(struct Gpio *pin, struct ChainedIsr *isr, IRQn_Type irqn)
+{
+ gpioConfigInput(pin, GPIO_SPEED_LOW, GPIO_PULL_NONE);
+ syscfgSetExtiPort(pin);
+ extiEnableIntGpio(pin, EXTI_TRIGGER_BOTH);
+ extiChainIsr(irqn, isr);
+ return true;
+}
+
+static bool disableInterrupt(struct Gpio *pin, struct ChainedIsr *isr, IRQn_Type irqn)
+{
+ extiUnchainIsr(irqn, isr);
+ extiDisableIntGpio(pin);
+ return true;
+}
+
+static const uint32_t supportedRates[] =
+{
+ SENSOR_RATE_ONCHANGE,
+ 0
+};
+
+static const struct SensorInfo mSensorInfo =
+{
+ .sensorName = "Hall",
+ .supportedRates = supportedRates,
+ .sensorType = SENS_TYPE_HALL,
+ .numAxis = NUM_AXIS_EMBEDDED,
+ .interrupt = NANOHUB_INT_WAKEUP,
+ .minSamples = 20
+};
+
+static bool hallPower(bool on, void *cookie)
+{
+ if (on) {
+ extiClearPendingGpio(mTask.sPin);
+ extiClearPendingGpio(mTask.nPin);
+ enableInterrupt(mTask.sPin, &mTask.sIsr, HALL_S_IRQ);
+ enableInterrupt(mTask.nPin, &mTask.nIsr, HALL_N_IRQ);
+ } else {
+ disableInterrupt(mTask.sPin, &mTask.sIsr, HALL_S_IRQ);
+ disableInterrupt(mTask.nPin, &mTask.nIsr, HALL_N_IRQ);
+ extiClearPendingGpio(mTask.sPin);
+ extiClearPendingGpio(mTask.nPin);
+ }
+
+ mTask.on = on;
+ mTask.prevReportedState = -1;
+
+ if (mTask.debounceTimerHandle) {
+ timTimerCancel(mTask.debounceTimerHandle);
+ mTask.debounceTimerHandle = 0;
+ }
+
+ return sensorSignalInternalEvt(mTask.sensorHandle, SENSOR_INTERNAL_EVT_POWER_STATE_CHG, on, 0);
+}
+
+static bool hallFirmwareUpload(void *cookie)
+{
+ return sensorSignalInternalEvt(mTask.sensorHandle, SENSOR_INTERNAL_EVT_FW_STATE_CHG, 1, 0);
+}
+
+static bool hallSetRate(uint32_t rate, uint64_t latency, void *cookie)
+{
+ // report initial state of hall interrupt pin
+ if (mTask.on)
+ hallReportState(MAKE_TYPE(gpioGet(mTask.sPin), gpioGet(mTask.nPin)));
+
+ return sensorSignalInternalEvt(mTask.sensorHandle, SENSOR_INTERNAL_EVT_RATE_CHG, rate, latency);
+}
+
+static bool hallFlush(void *cookie)
+{
+ return osEnqueueEvt(sensorGetMyEventType(SENS_TYPE_HALL), SENSOR_DATA_EVENT_FLUSH, NULL);
+}
+
+static bool hallSendLastSample(void *cookie, uint32_t tid)
+{
+ union EmbeddedDataPoint sample;
+ bool result = true;
+
+ if (mTask.prevReportedState != -1) {
+ sample.idata = mTask.prevReportedState;
+ result = osEnqueuePrivateEvt(sensorGetMyEventType(SENS_TYPE_HALL), sample.vptr, NULL, tid);
+ }
+
+ return result;
+}
+
+static const struct SensorOps mSensorOps =
+{
+ .sensorPower = hallPower,
+ .sensorFirmwareUpload = hallFirmwareUpload,
+ .sensorSetRate = hallSetRate,
+ .sensorFlush = hallFlush,
+ .sensorSendOneDirectEvt = hallSendLastSample
+};
+
+static void handleEvent(uint32_t evtType, const void* evtData)
+{
+}
+
+static bool startTask(uint32_t taskId)
+{
+ mTask.id = taskId;
+ mTask.sensorHandle = sensorRegister(&mSensorInfo, &mSensorOps, NULL, true);
+ mTask.prevReportedState = -1;
+ mTask.sPin = gpioRequest(HALL_S_PIN);
+ mTask.nPin = gpioRequest(HALL_N_PIN);
+ mTask.sIsr.func = hallSouthIsr;
+ mTask.nIsr.func = hallNorthIsr;
+
+ return true;
+}
+
+static void endTask(void)
+{
+ disableInterrupt(mTask.sPin, &mTask.sIsr, HALL_S_IRQ);
+ disableInterrupt(mTask.nPin, &mTask.nIsr, HALL_N_IRQ);
+ extiUnchainIsr(HALL_S_IRQ, &mTask.sIsr);
+ extiUnchainIsr(HALL_N_IRQ, &mTask.nIsr);
+ extiClearPendingGpio(mTask.sPin);
+ extiClearPendingGpio(mTask.nPin);
+ gpioRelease(mTask.sPin);
+ gpioRelease(mTask.nPin);
+ sensorUnregister(mTask.sensorHandle);
+ memset(&mTask, 0, sizeof(struct SensorTask));
+}
+
+INTERNAL_APP_INIT(APP_ID, APP_VERSION, startTask, endTask, handleEvent);