aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gpio.c254
-rw-r--r--src/gpio.h101
2 files changed, 355 insertions, 0 deletions
diff --git a/src/gpio.c b/src/gpio.c
new file mode 100644
index 0000000..93fc7a6
--- /dev/null
+++ b/src/gpio.c
@@ -0,0 +1,254 @@
+#include "gpio.h"
+#include "peripherals.h"
+#include "types.h"
+
+#define WRITE_PIN_CNF(pin, value) WRITE_GPIO_REG(pin, value)
+#define READ_PIN_CNF(pin) READ_GPIO_REG(pin)
+
+#define WRITE_GPIO_REG(reg, value) WRITE_REGISTER(P0, reg, value)
+#define READ_GPIO_REG(reg) READ_REGISTER(P0, reg)
+
+/**
+ * Available behaviours for the DETECT signal.
+ * `PIN_DETECT` combines every individuals PIN's DETECT signal.
+ * `LDETECT` uses the LDETECT signal.
+ */
+enum gpio_detect_mode {
+ PIN_DETECT = 0,
+ LDETECT = 1,
+};
+
+/**
+ * GPIO direction for each pin.
+ * When a GPIO is in disabled state, we forcefully put it in INPUT mode.
+ */
+enum gpio_direction {
+ INPUT = 0,
+ OUTPUT = 1,
+};
+
+/**
+ * The pull configuration for a GPIO line.
+ */
+enum gpio_pull_configuration {
+ /** Keep the GPIO in a floating state when the circuit is open */
+ NO_PULL = 0,
+
+ /** Force the signal to the `LOW` level when the circuit is open */
+ PULL_DOWN = 1,
+
+ /** Force the signal to the `HIGH` level when the circuit is open */
+ PULL_UP = 3,
+};
+
+/**
+ * The drive configuration for a GPIO line.
+ */
+enum gpio_drive_configuration {
+ /** Standard 0, Standard 1 */
+ S0S1 = 0,
+
+ /** High drive 0, Standard 1 */
+ H0S1 = 1,
+
+ /** Standard 0, High drive 1 */
+ S0H1 = 2,
+
+ /** High drive 0, High Drive 1 */
+ H0H1 = 3,
+
+ /** Disconnect 0, Standard 1 */
+ D0S1 = 4,
+
+ /** Disconnect 0, High drive 1 */
+ D0H1 = 5,
+
+ /** Standard 0, Disconnect 1 */
+ S0D1 = 6,
+
+ /** High drive 0, Disconnect 1 */
+ H0D1 = 7,
+};
+
+struct pin_configuration {
+ enum gpio_direction direction;
+ union {
+ struct {
+ enum gpio_pull_configuration pull_config;
+ enum gpio_level sensibility;
+ } input;
+
+ struct {
+ enum gpio_drive_configuration drive_config;
+ } output;
+ } config;
+};
+
+/**
+ * The hardcoded configuration for each GPIO pin.
+ */
+static const struct pin_configuration pins_configs[32] = {
+ [PIN_DISPLAY_SPI_CLOCK] = {
+ .direction = OUTPUT,
+ .config = {
+ .output = {
+ .drive_config = S0S1,
+ },
+ },
+ },
+};
+
+/**
+ * Memory-mapped register for the GPIO peripheral with their offset from its base address.
+ * Check the nrf52832's manual for their description.
+ */
+enum gpio_register {
+ OUT = 0x504,
+ OUTSET = 0x508,
+ OUTCLR = 0x50c,
+ IN = 0x510,
+ DIR = 0x514,
+ DIRSET = 0x518,
+ DIRCLR = 0x51c,
+ LATCH = 0x520,
+ DETECTMODE = 0x524,
+ PIN_CNF_0 = 0x700,
+ PIN_CNF_1 = 0x704,
+ PIN_CNF_2 = 0x708,
+ PIN_CNF_3 = 0x70c,
+ PIN_CNF_4 = 0x71c,
+ PIN_CNF_5 = 0x714,
+ PIN_CNF_6 = 0x718,
+ PIN_CNF_7 = 0x71c,
+ PIN_CNF_8 = 0x720,
+ PIN_CNF_9 = 0x724,
+ PIN_CNF_10 = 0x728,
+ PIN_CNF_11 = 0x72c,
+ PIN_CNF_12 = 0x730,
+ PIN_CNF_13 = 0x734,
+ PIN_CNF_14 = 0x738,
+ PIN_CNF_15 = 0x73c,
+ PIN_CNF_16 = 0x740,
+ PIN_CNF_17 = 0x744,
+ PIN_CNF_18 = 0x748,
+ PIN_CNF_19 = 0x74c,
+ PIN_CNF_20 = 0x750,
+ PIN_CNF_21 = 0x754,
+ PIN_CNF_22 = 0x758,
+ PIN_CNF_23 = 0x75c,
+ PIN_CNF_24 = 0x760,
+ PIN_CNF_25 = 0x764,
+ PIN_CNF_26 = 0x768,
+ PIN_CNF_27 = 0x76c,
+ PIN_CNF_28 = 0x770,
+ PIN_CNF_29 = 0x774,
+ PIN_CNF_30 = 0x778,
+ PIN_CNF_31 = 0x77c,
+};
+
+/**
+ * The offset of each pin configuration register from the GPIO base address.
+ */
+static const u32 cnf_offsets[] = {
+ [PIN_0] = PIN_CNF_0,
+ [PIN_1] = PIN_CNF_1,
+ [PIN_2] = PIN_CNF_2,
+ [PIN_3] = PIN_CNF_3,
+ [PIN_4] = PIN_CNF_4,
+ [PIN_5] = PIN_CNF_5,
+ [PIN_6] = PIN_CNF_6,
+ [PIN_7] = PIN_CNF_7,
+ [PIN_8] = PIN_CNF_8,
+ [PIN_9] = PIN_CNF_9,
+ [PIN_10] = PIN_CNF_10,
+ [PIN_11] = PIN_CNF_11,
+ [PIN_12] = PIN_CNF_12,
+ [PIN_13] = PIN_CNF_13,
+ [PIN_14] = PIN_CNF_14,
+ [PIN_15] = PIN_CNF_15,
+ [PIN_16] = PIN_CNF_16,
+ [PIN_17] = PIN_CNF_17,
+ [PIN_18] = PIN_CNF_18,
+ [PIN_19] = PIN_CNF_19,
+ [PIN_20] = PIN_CNF_20,
+ [PIN_21] = PIN_CNF_21,
+ [PIN_22] = PIN_CNF_22,
+ [PIN_23] = PIN_CNF_23,
+ [PIN_24] = PIN_CNF_24,
+ [PIN_25] = PIN_CNF_25,
+ [PIN_26] = PIN_CNF_26,
+ [PIN_27] = PIN_CNF_27,
+ [PIN_28] = PIN_CNF_28,
+ [PIN_29] = PIN_CNF_29,
+ [PIN_30] = PIN_CNF_30,
+ [PIN_31] = PIN_CNF_31,
+};
+
+/**
+ * We consider that a pin is active if it's in `INPUT` mode
+ * but has its detect mechanism disabled (the SENSE field of
+ * its configuration register is 0).
+ *
+ * Warning: that does not mean the pin is not already used elsewhere.
+ * Peripherals or drivers can put a pin in this state for whatever reason.
+ * Always make sure that the pin is not currently is use before doing
+ * anything with it.
+ */
+static u8 is_pin_active(enum gpio_pin pin) {
+ u32 conf = READ_PIN_CNF(cnf_offsets[pin]);
+
+ enum gpio_direction dir = conf & 0x1;
+ u8 sense = (conf >> 16) & 0x3;
+
+ return (dir != INPUT) || (sense != 0);
+}
+
+void gpio_init_pin(enum gpio_pin pin) {
+ u32 pin_reg = cnf_offsets[pin];
+ struct pin_configuration pin_config = pins_configs[pin];
+
+ u32 pin_reg_value = 0;
+ pin_reg_value |= pin_config.direction & 0x1;
+
+ if (pin_config.direction == INPUT) {
+ pin_reg_value |= (pin_config.config.input.pull_config & 0x3) << 2;
+ pin_reg_value |= (pin_config.config.input.sensibility & 0x3) << 16;
+ } else {
+ pin_reg_value |= (pin_config.config.output.drive_config & 0x7) << 8;
+ }
+
+ WRITE_PIN_CNF(pin_reg, pin_reg_value);
+}
+
+u8 gpio_disable_pin(enum gpio_pin pin) {
+ u32 pin_cnf_value = 0x0;
+
+ if (!is_pin_active(pin)) {
+ return 0;
+ }
+
+ /* INPUT mode with detection mechanism disabled */
+ pin_cnf_value |= INPUT & 0x1;
+
+ WRITE_PIN_CNF(cnf_offsets[pin], pin_cnf_value);
+
+ return 1;
+}
+
+
+enum gpio_level gpio_read_pin(enum gpio_pin pin) {
+ u32 pins_level = READ_GPIO_REG(IN);
+
+ return (pins_level >> pin) & 0x1;
+}
+
+u8 gpio_write_pin(enum gpio_pin pin, enum gpio_level level) {
+ enum gpio_register reg = level == HIGH ? OUTSET : OUTCLR;
+
+ if (pins_configs[pin].direction != OUTPUT) {
+ return 1;
+ }
+
+ WRITE_GPIO_REG(reg, (1 << pin));
+ return 0;
+}
diff --git a/src/gpio.h b/src/gpio.h
new file mode 100644
index 0000000..adcf76a
--- /dev/null
+++ b/src/gpio.h
@@ -0,0 +1,101 @@
+#ifndef GPIO_H
+#define GPIO_H
+
+#include "types.h"
+
+/* GPIO pins used for the LCD display */
+#define PIN_DISPLAY_SPI_CLOCK PIN_2
+#define PIN_DISPLAY_SPI_MOSI PIN_3
+#define PIN_DISPLAY_COMMAND_DATA PIN_18
+#define PIN_DISPLAY_CHIP_SELECT PIN_25
+#define PIN_DISPLAY_RESET PIN_26
+
+/* GPIO pins used for the touch panel */
+#define PIN_TOUCH_PANEL_RESET PIN_10
+#define PIN_TOUCH_PANEL_IRQ PIN_28
+#define PIN_TOUCH_PANEL_I2C_SDA PIN_06
+#define PIN_TOUCH_PANEL_I2C_SCL PIN_07
+
+/* GPIO pins used for the battery management */
+#define PIN_BATTERY_CHARGE_INDICATOR PIN_12
+#define PIN_BATTERY_VOLTAGE PIN_31
+
+/* GPIO pins used for the button */
+#define PIN_BUTTON_ENABLE PIN_15
+#define PIN_BUTTON_PRESS PIN_13
+
+/* GPIO pins used for the accelerometer */
+#define PIN_ACCEL_I2C_SDA PIN_06
+#define PIN_ACCEL_I2C_SCL PIN_07
+#define PIN_ACCEL_IRQ PIN_08
+
+/**
+ * The signal level of a GPIO line.
+ */
+enum gpio_level {
+ LOW = 0,
+ HIGH = 1,
+};
+
+/**
+ * The availables GPIO pins on the NRF82832.
+ */
+enum gpio_pin {
+ PIN_0 = 0,
+ PIN_1 = 1,
+ PIN_2 = 2,
+ PIN_3 = 3,
+ PIN_4 = 4,
+ PIN_5 = 5,
+ PIN_6 = 6,
+ PIN_7 = 7,
+ PIN_8 = 8,
+ PIN_9 = 9,
+ PIN_10 = 10,
+ PIN_11 = 11,
+ PIN_12 = 12,
+ PIN_13 = 13,
+ PIN_14 = 14,
+ PIN_15 = 15,
+ PIN_16 = 16,
+ PIN_17 = 17,
+ PIN_18 = 18,
+ PIN_19 = 19,
+ PIN_20 = 20,
+ PIN_21 = 21,
+ PIN_22 = 22,
+ PIN_23 = 23,
+ PIN_24 = 24,
+ PIN_25 = 25,
+ PIN_26 = 26,
+ PIN_27 = 27,
+ PIN_28 = 28,
+ PIN_29 = 29,
+ PIN_30 = 30,
+ PIN_31 = 31,
+};
+
+/**
+ * Init the given pin.
+ * Note that each pin configuration is hardcoded to fit the peripheral it is connected to.
+ */
+void gpio_init_pin(enum gpio_pin pin);
+
+/**
+ * Disable a GPIO pin.
+ */
+u8 gpio_disable_pin(enum gpio_pin pin);
+
+/**
+ * Read the current signal level of the given GPIO pin.
+ */
+enum gpio_level gpio_read_pin(enum gpio_pin pin);
+
+/**
+ * Set the given GPIO pin to the given level.
+ * Returns 0 if the given pin is not an output pin.
+ * Returns 1 if written successfully
+ */
+u8 gpio_write_pin(enum gpio_pin pin, enum gpio_level level);
+
+#endif