summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVic (Chun-Ju) Yang <victoryang@chromium.org>2014-04-22 10:05:48 +0800
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-04-30 09:49:01 +0000
commit1b7573c3e9484b35ee62c1160719076e8e9d8837 (patch)
tree29fc82e326c65ddadebc9c41dc9dcea9962b3bb0
parent39588b067fe2411a326fcec23a5df6584f20fab7 (diff)
downloadchrome-ec-1b7573c3e9484b35ee62c1160719076e8e9d8837.tar.gz
Keyborg: implement matrix scanning
This implements dual chip matrix scanning. Now the scan result is only dumped to debug output. BUG=None TEST=Put a finger on the panel and see its shape. BRANCH=None Change-Id: I015c901b42e24fe4a6249c12c37bc5bfcb308c9f Signed-off-by: Vic (Chun-Ju) Yang <victoryang@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/196468 Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r--board/keyborg/board.c119
-rw-r--r--board/keyborg/build.mk2
-rw-r--r--board/keyborg/hardware.c12
-rw-r--r--board/keyborg/spi_comm.c3
-rw-r--r--board/keyborg/spi_comm.h1
-rw-r--r--board/keyborg/touch_scan.c262
-rw-r--r--board/keyborg/touch_scan.h60
-rw-r--r--chip/stm32/registers.h23
8 files changed, 479 insertions, 3 deletions
diff --git a/board/keyborg/board.c b/board/keyborg/board.c
index 7616a0aaac..f609395316 100644
--- a/board/keyborg/board.c
+++ b/board/keyborg/board.c
@@ -12,12 +12,123 @@
#include "spi_comm.h"
#include "system.h"
#include "task.h"
+#include "touch_scan.h"
#include "util.h"
+const struct ts_pin row_pins[] = {
+ {TS_GPIO_E, 0}, /* R1 */
+ {TS_GPIO_E, 4}, /* R2 */
+ {TS_GPIO_E, 8}, /* R3 */
+ {TS_GPIO_E, 1}, /* R4 */
+ {TS_GPIO_E, 11}, /* R5 */
+ {TS_GPIO_E, 12}, /* R6 */
+ {TS_GPIO_E, 15}, /* R7 */
+ {TS_GPIO_E, 13}, /* R8 */
+ {TS_GPIO_D, 3}, /* R9 */
+ {TS_GPIO_D, 4}, /* R10 */
+ {TS_GPIO_D, 5}, /* R11 */
+ {TS_GPIO_D, 0}, /* R12 */
+ {TS_GPIO_D, 6}, /* R13 */
+ {TS_GPIO_D, 8}, /* R14 */
+ {TS_GPIO_D, 11}, /* R15 */
+ {TS_GPIO_D, 10}, /* R16 */
+ {TS_GPIO_D, 12}, /* R17 */
+ {TS_GPIO_D, 13}, /* R18 */
+ {TS_GPIO_D, 14}, /* R19 */
+ {TS_GPIO_D, 15}, /* R20 */
+ {TS_GPIO_C, 8}, /* R21 */
+ {TS_GPIO_C, 7}, /* R22 */
+ {TS_GPIO_C, 15}, /* R23 */
+ {TS_GPIO_E, 6}, /* R24 */
+ {TS_GPIO_E, 5}, /* R25 */
+ {TS_GPIO_E, 2}, /* R26 */
+ {TS_GPIO_E, 3}, /* R27 */
+ {TS_GPIO_E, 10}, /* R28 */
+ {TS_GPIO_E, 9}, /* R29 */
+ {TS_GPIO_E, 14}, /* R30 */
+ {TS_GPIO_E, 7}, /* R31 */
+ {TS_GPIO_D, 2}, /* R32 */
+ {TS_GPIO_D, 7}, /* R33 */
+ {TS_GPIO_D, 1}, /* R34 */
+ {TS_GPIO_D, 9}, /* R35 */
+ {TS_GPIO_C, 5}, /* R36 */
+ {TS_GPIO_C, 6}, /* R37 */
+ {TS_GPIO_C, 10}, /* R38 */
+ {TS_GPIO_C, 13}, /* R39 */
+ {TS_GPIO_C, 14}, /* R40 */
+ {TS_GPIO_C, 12}, /* R41 */
+};
+BUILD_ASSERT(ARRAY_SIZE(row_pins) == ROW_COUNT);
+
+const struct ts_pin col_pins[] = {
+ {TS_GPIO_B, 5}, /* C1 */
+ {TS_GPIO_H, 1}, /* C2 */
+ {TS_GPIO_H, 0}, /* C3 */
+ {TS_GPIO_H, 5}, /* C4 */
+ {TS_GPIO_H, 10}, /* C5 */
+ {TS_GPIO_H, 6}, /* C6 */
+ {TS_GPIO_H, 4}, /* C7 */
+ {TS_GPIO_H, 3}, /* C8 */
+ {TS_GPIO_H, 9}, /* C9 */
+ {TS_GPIO_H, 12}, /* C10 */
+ {TS_GPIO_H, 11}, /* C11 */
+ {TS_GPIO_H, 15}, /* C12 */
+ {TS_GPIO_H, 2}, /* C13 */
+ {TS_GPIO_H, 14}, /* C14 */
+ {TS_GPIO_G, 5}, /* C15 */
+ {TS_GPIO_G, 9}, /* C16 */
+ {TS_GPIO_G, 4}, /* C17 */
+ {TS_GPIO_G, 15}, /* C18 */
+ {TS_GPIO_G, 10}, /* C19 */
+ {TS_GPIO_G, 12}, /* C20 */
+ {TS_GPIO_G, 0}, /* C21 */
+ {TS_GPIO_G, 11}, /* C22 */
+ {TS_GPIO_B, 0}, /* C23 */
+ {TS_GPIO_G, 2}, /* C24 */
+ {TS_GPIO_G, 1}, /* C25 */
+ {TS_GPIO_A, 10}, /* Fake C26. C26 is used by debugger. */
+ {TS_GPIO_A, 10}, /* Fake C27. C27 is used by debugger. */
+ {TS_GPIO_B, 3}, /* C28 */
+ {TS_GPIO_A, 10}, /* Fake C29. C29 is used as UART Tx. */
+ {TS_GPIO_B, 8}, /* C30 */
+ {TS_GPIO_A, 10}, /* C31 */
+ {TS_GPIO_B, 1}, /* C32 */
+ {TS_GPIO_G, 13}, /* C33 */
+ {TS_GPIO_B, 7}, /* C34 */
+ {TS_GPIO_B, 2}, /* C35 */
+ {TS_GPIO_G, 14}, /* C36 */
+ {TS_GPIO_G, 3}, /* C37 */
+ {TS_GPIO_G, 7}, /* C38 */
+ {TS_GPIO_H, 13}, /* C39 */
+ {TS_GPIO_H, 7}, /* C40 */
+ {TS_GPIO_B, 4}, /* C41 */
+ {TS_GPIO_H, 8}, /* C42 */
+ {TS_GPIO_B, 6}, /* C43 */
+ {TS_GPIO_B, 9}, /* C44 */
+ {TS_GPIO_I, 10}, /* C45 */
+ {TS_GPIO_I, 11}, /* C46 */
+ {TS_GPIO_I, 9}, /* C47 */
+ {TS_GPIO_G, 8}, /* C48 */
+ {TS_GPIO_G, 6}, /* C49 */
+ {TS_GPIO_I, 4}, /* C50 */
+ {TS_GPIO_I, 3}, /* C51 */
+ {TS_GPIO_I, 5}, /* C52 */
+ {TS_GPIO_I, 14}, /* C53 */
+ {TS_GPIO_I, 12}, /* C54 */
+ {TS_GPIO_I, 8}, /* C55 */
+ {TS_GPIO_I, 6}, /* C56 */
+ {TS_GPIO_I, 15}, /* C57 */
+ {TS_GPIO_I, 0}, /* C58 */
+ {TS_GPIO_I, 13}, /* C59 */
+ {TS_GPIO_I, 7}, /* C60 */
+};
+BUILD_ASSERT(ARRAY_SIZE(col_pins) == COL_COUNT);
+
int main(void)
{
int i = 0;
hardware_init();
+ touch_scan_init();
debug_printf("Keyborg starting...\n");
master_slave_init();
@@ -43,6 +154,14 @@ int main(void)
debug_printf("Passed\n");
else
debug_printf("Failed\n");
+ task_wait_event(SECOND);
+ debug_printf("Scan...");
+ if (touch_scan_full_matrix() == EC_SUCCESS)
+ debug_printf("Passed\n");
+ else {
+ debug_printf("Failed\n");
+ task_wait_event(-1);
+ }
}
}
}
diff --git a/board/keyborg/build.mk b/board/keyborg/build.mk
index c0ee425972..b31dafce38 100644
--- a/board/keyborg/build.mk
+++ b/board/keyborg/build.mk
@@ -9,5 +9,5 @@ CHIP:=stm32
CHIP_FAMILY:=stm32f
CHIP_VARIANT:=stm32ts60
-board-y=board.o hardware.o runtime.o master_slave.o spi_comm.o
+board-y=board.o hardware.o runtime.o master_slave.o spi_comm.o touch_scan.o
board-$(CONFIG_DEBUG_PRINTF)+=debug.o
diff --git a/board/keyborg/hardware.c b/board/keyborg/hardware.c
index 3d140533f2..6651cf5b46 100644
--- a/board/keyborg/hardware.c
+++ b/board/keyborg/hardware.c
@@ -9,6 +9,7 @@
#include "registers.h"
#include "task.h"
#include "timer.h"
+#include "touch_scan.h"
#include "util.h"
static void clock_init(void)
@@ -113,8 +114,8 @@ static void adc_init(void)
/* Set right alignment */
STM32_ADC_CR2(id) &= ~(1 << 11);
- /* Set sampling time to 28.5 cycles */
- STM32_ADC_SMPR2(id) = 0x3;
+ /* Set sampling time */
+ STM32_ADC_SMPR2(id) = ADC_SMPR_VAL;
/* Select AIN0 */
STM32_ADC_SQR3(id) &= ~0x1f;
@@ -168,6 +169,12 @@ static void irq_init(void)
asm("cpsie i");
}
+static void pmse_init(void)
+{
+ /* Use 10K-ohm pull down */
+ STM32_PMSE_CR |= (1 << 13);
+}
+
void hardware_init(void)
{
power_init();
@@ -176,4 +183,5 @@ void hardware_init(void)
timers_init();
adc_init();
irq_init();
+ pmse_init();
}
diff --git a/board/keyborg/spi_comm.c b/board/keyborg/spi_comm.c
index 95f3ac9762..8d459d3ae5 100644
--- a/board/keyborg/spi_comm.c
+++ b/board/keyborg/spi_comm.c
@@ -13,6 +13,7 @@
#include "spi_comm.h"
#include "task.h"
#include "timer.h"
+#include "touch_scan.h"
#include "util.h"
#define DUMMY_DATA 0xdd
@@ -431,6 +432,8 @@ static void spi_nss_interrupt(void)
if (cmd->cmd_sts == TS_CMD_HELLO)
spi_slave_hello_back(cmd);
+ else if (cmd->cmd_sts == TS_CMD_FULL_SCAN)
+ touch_scan_slave_start();
else
spi_slave_nack();
}
diff --git a/board/keyborg/spi_comm.h b/board/keyborg/spi_comm.h
index 4a1abb632a..8000503e8f 100644
--- a/board/keyborg/spi_comm.h
+++ b/board/keyborg/spi_comm.h
@@ -10,6 +10,7 @@
enum ts_command {
TS_CMD_HELLO = 0,
+ TS_CMD_FULL_SCAN,
};
struct spi_comm_packet {
diff --git a/board/keyborg/touch_scan.c b/board/keyborg/touch_scan.c
new file mode 100644
index 0000000000..3867a4ee96
--- /dev/null
+++ b/board/keyborg/touch_scan.c
@@ -0,0 +1,262 @@
+/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Touch scanning module */
+
+#include "common.h"
+#include "console.h"
+#include "debug.h"
+#include "dma.h"
+#include "gpio.h"
+#include "hooks.h"
+#include "master_slave.h"
+#include "registers.h"
+#include "spi_comm.h"
+#include "timer.h"
+#include "touch_scan.h"
+#include "util.h"
+
+#define TS_PIN_TO_CR(p) ((((p).port_id + 1) << 16) | (1 << (p).pin))
+#define TS_GPIO_TO_BASE(p) (0x40010800 + (p) * 0x400)
+
+/*
+ * Storage for partial touch scan data. This will be smaller once
+ * we figure out how to encode it.
+ */
+static uint8_t touch_data[COL_COUNT + 10][ROW_COUNT * 2];
+
+static uint8_t buf[ROW_COUNT * 2];
+
+static uint32_t mccr_list[COL_COUNT];
+static uint32_t mrcr_list[ROW_COUNT];
+
+static void set_gpio(const struct ts_pin pin, enum pin_type type)
+{
+ uint32_t addr, mode, mask;
+ uint32_t port = TS_GPIO_TO_BASE(pin.port_id);
+ uint32_t pmask = 1 << pin.pin;
+
+ if (pmask & 0xff) {
+ addr = port;
+ mode = pmask;
+ } else {
+ addr = port + 0x04;
+ mode = pmask >> 8;
+ }
+ mode = mode * mode * mode * mode * 0xf;
+
+ mask = REG32(addr) & ~mode;
+
+ if (type == PIN_COL) {
+ /* Alternate output open-drain */
+ mask |= 0xdddddddd & mode;
+ } else if (type == PIN_PD) {
+ mask |= 0x88888888 & mode;
+ STM32_GPIO_BSRR(port) = pmask << 16;
+ } else if (type == PIN_ROW) {
+ /* Nothing for PIN_ROW. Already analog input. */
+ }
+
+ REG32(addr) = mask;
+}
+
+void touch_scan_init(void)
+{
+ int i;
+
+ for (i = 0; i < ROW_COUNT; ++i) {
+ set_gpio(col_pins[i], PIN_ROW);
+ STM32_PMSE_PxPMR(row_pins[i].port_id) |= 1 << row_pins[i].pin;
+ }
+ for (i = 0; i < COL_COUNT; ++i)
+ set_gpio(col_pins[i], PIN_PD);
+
+ for (i = 0; i < ROW_COUNT; ++i)
+ mrcr_list[i] = TS_PIN_TO_CR(row_pins[i]);
+ for (i = 0; i < COL_COUNT; ++i)
+ mccr_list[i] = TS_PIN_TO_CR(col_pins[i]);
+}
+
+static void start_adc_sample(int id, int wait_cycle)
+{
+ /* Clear EOC and STRT bit */
+ STM32_ADC_SR(id) &= ~((1 << 1) | (1 << 4));
+
+ /* Start conversion */
+ STM32_ADC_CR2(id) |= (1 << 0);
+
+ /* Wait for conversion start */
+ while (!(STM32_ADC_SR(id) & (1 << 4)))
+ ;
+
+ /* Each iteration takes 3 CPU cycles */
+ asm("1: subs %0, #1\n"
+ " bne 1b\n" :: "r"(wait_cycle / 3));
+}
+
+#if ADC_SMPL_CYCLE_2 < ADC_CONV_CYCLE_2 * 2
+static uint16_t flush_adc(int id)
+{
+ while (!(STM32_ADC_SR(id) & (1 << 1)))
+ ;
+ return STM32_ADC_DR(id) & ADC_READ_MAX;
+}
+#else
+#define flush_adc(x) STM32_ADC_DR(x)
+#endif
+
+static void enable_col(int idx, int enabled)
+{
+ if (enabled) {
+ set_gpio(col_pins[idx], PIN_COL);
+ STM32_PMSE_PxPMR(col_pins[idx].port_id) |=
+ 1 << col_pins[idx].pin;
+ } else {
+ set_gpio(col_pins[idx], PIN_PD);
+ STM32_PMSE_PxPMR(col_pins[idx].port_id) &=
+ ~(1 << col_pins[idx].pin);
+ }
+}
+
+void scan_column(uint8_t *data)
+{
+ int i;
+
+ STM32_PMSE_MRCR = mrcr_list[0];
+ start_adc_sample(0, ADC_LONG_CPU_CYCLE);
+ STM32_PMSE_MRCR = mrcr_list[1];
+ start_adc_sample(1, ADC_LONG_CPU_CYCLE);
+
+ for (i = 2; i < ROW_COUNT; ++i) {
+ data[i - 2] = ADC_DATA_WINDOW(flush_adc(i & 1));
+ STM32_PMSE_MRCR = mrcr_list[i];
+ start_adc_sample(i & 1, ADC_SHORT_CPU_CYCLE);
+ }
+
+ while (!(STM32_ADC_SR(ROW_COUNT & 1) & (1 << 1)))
+ ;
+ data[ROW_COUNT - 2] = ADC_DATA_WINDOW(flush_adc(ROW_COUNT & 1));
+ while (!(STM32_ADC_SR((ROW_COUNT & 1) ^ 1) & (1 << 1)))
+ ;
+ data[ROW_COUNT - 1] = ADC_DATA_WINDOW(flush_adc((ROW_COUNT & 1) ^ 1));
+}
+
+void touch_scan_slave_start(void)
+{
+ int col, i;
+ struct spi_comm_packet *resp = (struct spi_comm_packet *)buf;
+
+ for (col = 0; col < COL_COUNT * 2; ++col) {
+ if (col >= COL_COUNT) {
+ enable_col(col - COL_COUNT, 1);
+ STM32_PMSE_MCCR = mccr_list[col - COL_COUNT];
+ }
+
+ if (master_slave_sync(20) != EC_SUCCESS)
+ return;
+
+ scan_column(resp->data);
+ resp->cmd_sts = EC_SUCCESS;
+
+ /* Trim trailing zeros. */
+ for (i = 0; i < ROW_COUNT; ++i)
+ if (resp->data[i] >= THRESHOLD)
+ resp->size = i;
+
+ /* Flush the last response */
+ if (col != 0)
+ spi_slave_send_response_flush();
+
+ if (master_slave_sync(20) != EC_SUCCESS)
+ return;
+
+ /* Start sending the response for the current column */
+ spi_slave_send_response_async(resp);
+
+ if (col >= COL_COUNT) {
+ enable_col(col - COL_COUNT, 0);
+ STM32_PMSE_MCCR = 0;
+ }
+ }
+ spi_slave_send_response_flush();
+ master_slave_sync(20);
+}
+
+int touch_scan_full_matrix(void)
+{
+ struct spi_comm_packet cmd;
+ const struct spi_comm_packet *resp;
+ int col, row;
+ timestamp_t st = get_time();
+ uint8_t *dptr = NULL, *last_dptr = NULL;
+
+ cmd.cmd_sts = TS_CMD_FULL_SCAN;
+ cmd.size = 0;
+
+ if (spi_master_send_command(&cmd))
+ return EC_ERROR_UNKNOWN;
+
+ for (col = 0; col < COL_COUNT * 2; ++col) {
+ if (col < COL_COUNT) {
+ enable_col(col, 1);
+ STM32_PMSE_MCCR = mccr_list[col];
+ }
+
+ if (master_slave_sync(20) != EC_SUCCESS)
+ return EC_ERROR_UNKNOWN;
+
+ last_dptr = dptr;
+ if (col < COL_COUNT + 10)
+ dptr = touch_data[col];
+ else
+ dptr = buf;
+
+ scan_column(dptr + ROW_COUNT);
+
+ if (col > 0) {
+ /* Flush the data from the slave for the last column */
+ resp = spi_master_wait_response_done();
+ if (resp == NULL)
+ return EC_ERROR_UNKNOWN;
+ memcpy(last_dptr, resp->data, resp->size);
+ memset(last_dptr + resp->size, 0,
+ ROW_COUNT - resp->size);
+ }
+
+ if (master_slave_sync(20) != EC_SUCCESS)
+ return EC_ERROR_UNKNOWN;
+
+ /* Start receiving data for the current column */
+ if (spi_master_wait_response_async() != EC_SUCCESS)
+ return EC_ERROR_UNKNOWN;
+
+ if (col < COL_COUNT) {
+ enable_col(col, 0);
+ STM32_PMSE_MCCR = 0;
+ }
+ }
+
+ resp = spi_master_wait_response_done();
+ if (resp == NULL)
+ return EC_ERROR_UNKNOWN;
+ memcpy(last_dptr, resp->data, resp->size);
+ memset(last_dptr + resp->size, 0, ROW_COUNT - resp->size);
+
+ master_slave_sync(20);
+
+ debug_printf("Sampling took %d us\n", get_time().val - st.val);
+
+ for (row = 0; row < ROW_COUNT * 2; ++row) {
+ for (col = 0; col < COL_COUNT + 10; ++col) {
+ if (touch_data[col][row] < THRESHOLD)
+ debug_printf(" - ");
+ else
+ debug_printf("%3d ", touch_data[col][row]);
+ }
+ debug_printf("\n");
+ }
+
+ return EC_SUCCESS;
+}
diff --git a/board/keyborg/touch_scan.h b/board/keyborg/touch_scan.h
new file mode 100644
index 0000000000..022c2b7d3e
--- /dev/null
+++ b/board/keyborg/touch_scan.h
@@ -0,0 +1,60 @@
+/* Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Touch scanning module */
+
+#ifndef __BOARD_KEYBORG_TOUCH_SCAN_H
+#define __BOARD_KEYBORG_TOUCH_SCAN_H
+
+enum pin_type {
+ PIN_ROW,
+ PIN_COL,
+ PIN_PD,
+};
+
+/* 8-bit window */
+#define ADC_WINDOW_POS 2
+#define ADC_DATA_WINDOW(x) ((x) >> ADC_WINDOW_POS)
+
+/* Threshold for each cell */
+#define THRESHOLD 35
+
+/* ADC speed */
+#define ADC_SMPR_VAL 0x3 /* 28.5 cycles */
+#define ADC_SMPL_CYCLE_2 57
+#define ADC_CONV_CYCLE_2 25
+
+/* CPU clock is 4 times faster than ADC clock */
+#define ADC_LONG_CPU_CYCLE (ADC_SMPL_CYCLE_2 * 2)
+#define ADC_SHORT_CPU_CYCLE ((ADC_SMPL_CYCLE_2 - ADC_CONV_CYCLE_2) * 2)
+
+struct ts_pin {
+ uint8_t port_id; /* GPIO_A = 0, GPIO_B = 1, ... */
+ uint8_t pin;
+};
+
+#define TS_GPIO_A 0
+#define TS_GPIO_B 1
+#define TS_GPIO_C 2
+#define TS_GPIO_D 3
+#define TS_GPIO_E 4
+#define TS_GPIO_F 5
+#define TS_GPIO_G 6
+#define TS_GPIO_H 7
+#define TS_GPIO_I 8
+
+extern const struct ts_pin row_pins[];
+extern const struct ts_pin col_pins[];
+
+#define ROW_COUNT 41
+#define COL_COUNT 60
+
+void touch_scan_init(void);
+
+void touch_scan_slave_start(void);
+
+int touch_scan_full_matrix(void);
+
+#endif /* __BOARD_KEYBORG_TOUCH_SCAN_H */
diff --git a/chip/stm32/registers.h b/chip/stm32/registers.h
index c6b2acef09..3741a38c69 100644
--- a/chip/stm32/registers.h
+++ b/chip/stm32/registers.h
@@ -1166,6 +1166,29 @@ typedef volatile struct stm32_dma_regs stm32_dma_regs_t;
#define STM32_CRC_CR_REV_IN_WORD (3 << 5)
#define STM32_CRC_CR_REV_OUT (1 << 7)
+/* --- PMSE --- */
+#define STM32_PMSE_BASE 0x40013400
+
+#define STM32_PMSE_ARCR REG32(STM32_PMSE_BASE + 0x0)
+#define STM32_PMSE_ACCR REG32(STM32_PMSE_BASE + 0x4)
+#define STM32_PMSE_CR REG32(STM32_PMSE_BASE + 0x8)
+#define STM32_PMSE_CRTDR REG32(STM32_PMSE_BASE + 0x14)
+#define STM32_PMSE_IER REG32(STM32_PMSE_BASE + 0x18)
+#define STM32_PMSE_SR REG32(STM32_PMSE_BASE + 0x1c)
+#define STM32_PMSE_IFCR REG32(STM32_PMSE_BASE + 0x20)
+#define STM32_PMSE_PxPMR(x) REG32(STM32_PMSE_BASE + 0x2c + (x) * 4)
+#define STM32_PMSE_PAPMR REG32(STM32_PMSE_BASE + 0x2c)
+#define STM32_PMSE_PBPMR REG32(STM32_PMSE_BASE + 0x30)
+#define STM32_PMSE_PCPMR REG32(STM32_PMSE_BASE + 0x34)
+#define STM32_PMSE_PDPMR REG32(STM32_PMSE_BASE + 0x38)
+#define STM32_PMSE_PEPMR REG32(STM32_PMSE_BASE + 0x3c)
+#define STM32_PMSE_PFPMR REG32(STM32_PMSE_BASE + 0x40)
+#define STM32_PMSE_PGPMR REG32(STM32_PMSE_BASE + 0x44)
+#define STM32_PMSE_PHPMR REG32(STM32_PMSE_BASE + 0x48)
+#define STM32_PMSE_PIPMR REG32(STM32_PMSE_BASE + 0x4c)
+#define STM32_PMSE_MRCR REG32(STM32_PMSE_BASE + 0x100)
+#define STM32_PMSE_MCCR REG32(STM32_PMSE_BASE + 0x104)
+
/* --- MISC --- */
#define STM32_CEC_BASE 0x40007800 /* STM32F100 only */