keyboard stuff
1// Copyright 2019 Mathias Andersson <wraul@dbox.se>
2// SPDX-License-Identifier: GPL-2.0-or-later
3#include "matrix.h"
4#include "pca9555.h"
5#include "wait.h"
6
7/*
8 * IC1 (PCA9555) IC2 (PCA9555)
9 * ,----------. ,----------.
10 * SDA --| SDA P00 |-- P1 SDA --| SDA P00 |-- P17
11 * SCL --| SCL P01 |-- P2 SCL --| SCL P01 |-- P18
12 * INT --| INT P02 |-- P3 INT --| INT P02 |-- P19
13 * | P03 |-- P4 | P03 |-- P20
14 * GND --| A0 P04 |-- P5 VCC --| A0 P04 |-- P21
15 * SJ1 --| A1 P05 |-- P6 SJ1 --| A1 P05 |-- P22
16 * GND --| A2 P06 |-- P7 GND --| A2 P06 |-- P23
17 * | P07 |-- P8 | P07 |-- P24
18 * | | | |
19 * | P10 |-- P9 | P10 |-- P25
20 * | P11 |-- P10 | P11 |-- P26
21 * | P12 |-- P11 | P12 |-- P27
22 * | P13 |-- P12 | P13 |-- P28
23 * | P14 |-- P13 | P14 |-- P29
24 * | P15 |-- P14 | P15 |-- P30
25 * | P16 |-- P15 | P16 |-- P31
26 * | P17 |-- P16 | P17 |-- P32
27 * `----------' `----------'
28 */
29
30/*
31 * | Row | Pin | | Col | Pin |
32 * | --- | --- | | --- | --- |
33 * | 0 | P1 | | 0 | P25 |
34 * | 1 | P2 | | 1 | P26 |
35 * | 2 | P3 | | 2 | P27 |
36 * | 3 | P4 | | 3 | P28 |
37 * | 4 | P5 | | 4 | P29 |
38 * | 5 | P6 | | 5 | P30 |
39 * | 6 | P7 | | 6 | P20 |
40 * | 7 | P8 | | 7 | P21 |
41 * | 8 | P22 |
42 * | 9 | P23 |
43 * | A | P24 |
44 */
45
46// PCA9555 slave addresses
47#define IC1 0x20
48#define IC2 0x21
49
50// PCA9555 column pin masks
51#define PORT0_COLS_MASK 0b11111000
52#define PORT1_COLS_MASK 0b00111111
53#define COLS_MASK 0b0000011111111111
54
55static void init_pins(void) {
56 // init cols - IC2 port0 & IC2 port1 input
57 pca9555_set_config(IC2, PCA9555_PORT0, ALL_INPUT);
58 pca9555_set_config(IC2, PCA9555_PORT1, ALL_INPUT);
59
60 // init rows - IC1 port0 output
61 pca9555_set_config(IC1, PCA9555_PORT0, ALL_OUTPUT);
62 pca9555_set_output(IC1, PCA9555_PORT0, ALL_HIGH);
63}
64
65static void select_row(uint8_t row) {
66 // All rows are on the same IC and port
67 uint8_t mask = 1 << row;
68
69 // set active row low : 0
70 // set other rows hi-Z : 1
71 pca9555_set_output(IC1, PCA9555_PORT0, ALL_HIGH & (~mask));
72}
73
74static uint16_t read_cols(void) {
75 uint8_t state_1 = 0;
76 uint8_t state_2 = 0;
77 pca9555_read_pins(IC2, PCA9555_PORT0, &state_1);
78 pca9555_read_pins(IC2, PCA9555_PORT1, &state_2);
79
80 uint16_t state = (((uint16_t)state_1 & PORT0_COLS_MASK) << 3) | (((uint16_t)state_2 & PORT1_COLS_MASK));
81
82 // A low pin indicates an active column
83 return (~state) & COLS_MASK;
84}
85
86static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) {
87 // Store last value of row prior to reading
88 matrix_row_t last_row_value = current_matrix[current_row];
89
90 // Clear data in matrix row
91 current_matrix[current_row] = 0;
92
93 // Select row and wait for row selection to stabilize
94 select_row(current_row);
95 wait_us(30);
96
97 current_matrix[current_row] = read_cols();
98
99 // No need to unselect as `select_row` sets all the pins.
100
101 return (last_row_value != current_matrix[current_row]);
102}
103
104void matrix_init_custom(void) {
105 pca9555_init(IC1);
106 pca9555_init(IC2);
107
108 init_pins();
109}
110
111bool matrix_scan_custom(matrix_row_t current_matrix[]) {
112 bool changed = false;
113 for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) {
114 changed |= read_cols_on_row(current_matrix, current_row);
115 }
116 return changed;
117}