summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Kühling <665506+dvdkhlng@users.noreply.github.com>2022-07-17 18:49:36 +0200
committerGitHub <noreply@github.com>2022-07-17 09:49:36 -0700
commit931c7539d25ad23376e2501c3861bbb38ed58d72 (patch)
tree097f5f72302b94930ed6523f5a4f531056b9cda6
parent747b33cb81ac2397419beac9653f9ce697a30b7b (diff)
[Keyboard] Handwired Maltron DQz11N1G contoured keyboard (#17237)
* Basic support for Maltron DQz11N1G controller replacement. * Update keyboards/handwired/dqz11n1g/rules.mk * Rehost images to cubeupload.com. (They were previously hosted via github wiki) * Apply suggestions from noroadsleft code review * Update keyboards/handwired/dqz11n1g/dqz11n1g.h
-rw-r--r--keyboards/handwired/dqz11n1g/config.h58
-rw-r--r--keyboards/handwired/dqz11n1g/dqz11n1g.h51
-rw-r--r--keyboards/handwired/dqz11n1g/info.json141
-rw-r--r--keyboards/handwired/dqz11n1g/keymaps/default/keymap.c72
-rw-r--r--keyboards/handwired/dqz11n1g/keymaps/default/readme.md17
-rw-r--r--keyboards/handwired/dqz11n1g/matrix.c131
-rw-r--r--keyboards/handwired/dqz11n1g/readme.md80
-rw-r--r--keyboards/handwired/dqz11n1g/rules.mk24
8 files changed, 574 insertions, 0 deletions
diff --git a/keyboards/handwired/dqz11n1g/config.h b/keyboards/handwired/dqz11n1g/config.h
new file mode 100644
index 0000000000..0631787f55
--- /dev/null
+++ b/keyboards/handwired/dqz11n1g/config.h
@@ -0,0 +1,58 @@
+/*
+Copyright (c) 2022 David Kuehling <dvdkhlng TA posteo TOD de>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#include "config_common.h"
+
+/* USB Device descriptor parameter */
+#define VENDOR_ID 0xFEED
+#define PRODUCT_ID 0x4451
+#define DEVICE_VER 0x0001
+#define PRODUCT DQz11N1G Controller Replacement
+
+/* Matrix size */
+#define MATRIX_ROWS 7
+#define MATRIX_COLS 19
+
+/* Pin-out */
+#define MATRIX_ROW_PINS { D1, D0, D4, C6, D7, E6, B4 }
+
+/* The pin connecting to the SN74HC165 SH/~LD in */
+#define ROW_SHIFT_PIN B6
+
+/* Column read via SPI (shift register) */
+/* #define MATRIX_COL_PINS { } */
+#define UNUSED_PINS
+
+#define LED_CAPS_LOCK_PIN F7 /* A0 */
+#define LED_NUM_LOCK_PIN F5 /*A2 */
+#define LED_SCROLL_LOCK_PIN F4 /*A3 */
+
+#define LED_FUN_LOCK_PIN F6 /* A1 (handled in layer_state_set_user()) */
+
+/* audio config */
+#define AUDIO_PIN B5
+#define AUDIO_CLICKY
+#define AUDIO_INIT_DELAY
+#define AUDIO_CLICKY_FREQ_RANDOMNESS 0.0f
+#define NO_MUSIC_MODE
+
+/* diodes go row->col, though this is hard-coded in matrix.c and we drive the
+ * matrix differently: we have pull-down on the columns and drive the selected
+ * row high */
+/* #define DIODE_DIRECTION ROW2COL */
diff --git a/keyboards/handwired/dqz11n1g/dqz11n1g.h b/keyboards/handwired/dqz11n1g/dqz11n1g.h
new file mode 100644
index 0000000000..f5c55bd6d5
--- /dev/null
+++ b/keyboards/handwired/dqz11n1g/dqz11n1g.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2022 David Kuehling <dvdkhlng TA posteo TOD de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include "quantum.h"
+
+#define XXX KC_NO
+
+/* Fill actually existing keys into the 7x19 keyboard matrix */
+#define LAYOUT( \
+ k00, k01, k02, k03, k04, k05, k06, k07, k08, k09, k0A, k0B, k0C, k0D, k0E, k0F, k0G, k0H, k0J, \
+ k10, k11, k12, k13, k14, k15, k16, k17, k18, k19, k1A, k1B, k1C, k1D, k1E, k1F, k1G, k1H, k1J, \
+ k20, k21, k22, k23, k24, k25, k26, k27, k28, k29, k2A, k2B, k2C, k2D, k2E, k2F, k2G, k2H, k2J, \
+ k30, k31, k32, k33, k34, k35, k36, k37, k38, k39, k3A, k3B, k3C, k3D, k3E, k3F, k3G, k3H, k3J, \
+ k40, k41, k42, k43, k44, k45, k4D, k4E, k4F, k4G, k4H, k4J, \
+ k51, k52, k53, k54, k5E, k5F, k5G, k5H, \
+ k46, k47, k48, k4A, k4B, k4C, \
+ k56, k57, k58, k5A, k5B, k5C, \
+ k68, k6A \
+) { \
+ /* left hand */ /* middle/thumb block */ /* right hand */ \
+ { k00, k01, k02, k03, k04, k05, k06, k07, k08, k09, k0A, k0B, k0C, k0D, k0E, k0F, k0G, k0H, k0J }, \
+ { k10, k11, k12, k13, k14, k15, k16, k17, k18, k19, k1A, k1B, k1C, k1D, k1E, k1F, k1G, k1H, k1J }, \
+ { k20, k21, k22, k23, k24, k25, k26, k27, k28, k29, k2A, k2B, k2C, k2D, k2E, k2F, k2G, k2H, k2J }, \
+ { k30, k31, k32, k33, k34, k35, k36, k37, k38, k39, k3A, k3B, k3C, k3D, k3E, k3F, k3G, k3H, k3J }, \
+ { k40, k41, k42, k43, k44, k45, k46, k47, k48, XXX, k4A, k4B, k4C, k4D, k4E, k4F, k4G, k4H, k4J }, \
+ { XXX, k51, k52, k53, k54, XXX, k56, k57, k58, XXX, k5A, k5B, k5C, XXX, k5E, k5F, k5G, k5H, XXX }, \
+ { XXX, XXX, XXX, XXX, XXX, XXX, XXX, XXX, k68, XXX, k6A, XXX, XXX, XXX, XXX, XXX, XXX, XXX, XXX }, \
+}
+
+/*
+ * Local Variables:
+ * c-basic-offset:4
+ * fill-column: 76
+ * End:
+ */
diff --git a/keyboards/handwired/dqz11n1g/info.json b/keyboards/handwired/dqz11n1g/info.json
new file mode 100644
index 0000000000..0c56752ffd
--- /dev/null
+++ b/keyboards/handwired/dqz11n1g/info.json
@@ -0,0 +1,141 @@
+{
+ "keyboard_name": "DQz11N1G",
+ "url": "https://github.com/dvdkhlng/qmk_firmware_dqz11n1g",
+ "maintainer": "dvdkhlng",
+ "layouts": {
+ "LAYOUT": {
+ "layout": [
+ {"x": 0, "y": 0, "matrix": [0, 0] },
+ {"x": 1, "y": 0, "matrix": [0, 1] },
+ {"x": 2, "y": 0, "matrix": [0, 2] },
+ {"x": 3, "y": 0, "matrix": [0, 3] },
+ {"x": 4, "y": 0, "matrix": [0, 4] },
+ {"x": 5, "y": 0, "matrix": [0, 5] },
+
+ {"x": 7, "y": 0, "matrix": [0, 6] },
+ {"x": 8, "y": 0, "matrix": [0, 7] },
+ {"x": 9, "y": 0, "matrix": [0, 8] },
+ {"x": 10, "y": 0, "matrix": [0, 9] },
+ {"x": 11, "y": 0, "matrix": [0, 10] },
+ {"x": 12, "y": 0, "matrix": [0, 11] },
+ {"x": 13, "y": 0, "matrix": [0, 12] },
+
+ {"x": 15, "y": 0, "matrix": [0, 13] },
+ {"x": 16, "y": 0, "matrix": [0, 14] },
+ {"x": 17, "y": 0, "matrix": [0, 15] },
+ {"x": 18, "y": 0, "matrix": [0, 16] },
+ {"x": 19, "y": 0, "matrix": [0, 17] },
+ {"x": 20, "y": 0, "matrix": [0, 18] },
+
+ {"x": 0, "y": 1, "matrix": [1, 0] },
+ {"x": 1, "y": 1, "matrix": [1, 1] },
+ {"x": 2, "y": 1, "matrix": [1, 2] },
+ {"x": 3, "y": 1, "matrix": [1, 3] },
+ {"x": 4, "y": 1, "matrix": [1, 4] },
+ {"x": 5, "y": 1, "matrix": [1, 5] },
+
+ {"x": 7, "y": 1, "matrix": [1, 6] },
+ {"x": 8, "y": 1, "matrix": [1, 7] },
+ {"x": 9, "y": 1, "matrix": [1, 8] },
+ {"x": 10, "y": 1, "matrix": [1, 9] },
+ {"x": 11, "y": 1, "matrix": [1, 10] },
+ {"x": 12, "y": 1, "matrix": [1, 11] },
+ {"x": 13, "y": 1, "matrix": [1, 12] },
+
+ {"x": 15, "y": 1, "matrix": [1, 13] },
+ {"x": 16, "y": 1, "matrix": [1, 14] },
+ {"x": 17, "y": 1, "matrix": [1, 15] },
+ {"x": 18, "y": 1, "matrix": [1, 16] },
+ {"x": 19, "y": 1, "matrix": [1, 17] },
+ {"x": 20, "y": 1, "matrix": [1, 18] },
+
+ {"x": 0, "y": 2, "matrix": [2, 0] },
+ {"x": 1, "y": 2, "matrix": [2, 1] },
+ {"x": 2, "y": 2, "matrix": [2, 2] },
+ {"x": 3, "y": 2, "matrix": [2, 3] },
+ {"x": 4, "y": 2, "matrix": [2, 4] },
+ {"x": 5, "y": 2, "matrix": [2, 5] },
+
+ {"x": 7, "y": 2, "matrix": [2, 6] },
+ {"x": 8, "y": 2, "matrix": [2, 7] },
+ {"x": 9, "y": 2, "matrix": [2, 8] },
+ {"x": 10, "y": 2, "matrix": [2, 9] },
+ {"x": 11, "y": 2, "matrix": [2, 10] },
+ {"x": 12, "y": 2, "matrix": [2, 11] },
+ {"x": 13, "y": 2, "matrix": [2, 12] },
+
+ {"x": 15, "y": 2, "matrix": [2, 13] },
+ {"x": 16, "y": 2, "matrix": [2, 14] },
+ {"x": 17, "y": 2, "matrix": [2, 15] },
+ {"x": 18, "y": 2, "matrix": [2, 16] },
+ {"x": 19, "y": 2, "matrix": [2, 17] },
+ {"x": 20, "y": 2, "matrix": [2, 18] },
+
+ {"x": 0, "y": 3, "matrix": [3, 0] },
+ {"x": 1, "y": 3, "matrix": [3, 1] },
+ {"x": 2, "y": 3, "matrix": [3, 2] },
+ {"x": 3, "y": 3, "matrix": [3, 3] },
+ {"x": 4, "y": 3, "matrix": [3, 4] },
+ {"x": 5, "y": 3, "matrix": [3, 5] },
+
+ {"x": 7, "y": 3, "matrix": [3, 6] },
+ {"x": 8, "y": 3, "matrix": [3, 7] },
+ {"x": 9, "y": 3, "matrix": [3, 8] },
+ {"x": 10, "y": 3, "matrix": [3, 9] },
+ {"x": 11, "y": 3, "matrix": [3, 10] },
+ {"x": 12, "y": 3, "matrix": [3, 11] },
+ {"x": 13, "y": 3, "matrix": [3, 12] },
+
+ {"x": 15, "y": 3, "matrix": [3, 13] },
+ {"x": 16, "y": 3, "matrix": [3, 14] },
+ {"x": 17, "y": 3, "matrix": [3, 15] },
+ {"x": 18, "y": 3, "matrix": [3, 16] },
+ {"x": 19, "y": 3, "matrix": [3, 17] },
+ {"x": 20, "y": 3, "matrix": [3, 18] },
+
+ {"x": 0, "y": 4, "h": 2, "matrix": [4, 0] },
+ {"x": 1, "y": 4, "matrix": [4, 1] },
+ {"x": 2, "y": 4, "matrix": [4, 2] },
+ {"x": 3, "y": 4, "matrix": [4, 3] },
+ {"x": 4, "y": 4, "matrix": [4, 4] },
+ {"x": 5, "y": 4, "matrix": [4, 5] },
+
+ {"x": 15, "y": 4, "matrix": [4, 13] },
+ {"x": 16, "y": 4, "matrix": [4, 14] },
+ {"x": 17, "y": 4, "matrix": [4, 15] },
+ {"x": 18, "y": 4, "matrix": [4, 16] },
+ {"x": 19, "y": 4, "matrix": [4, 17] },
+ {"x": 20, "y": 4, "h": 2, "matrix": [4, 18] },
+
+ {"x": 1, "y": 5, "matrix": [5, 1] },
+ {"x": 2, "y": 5, "matrix": [5, 2] },
+ {"x": 3, "y": 5, "matrix": [5, 3] },
+ {"x": 4, "y": 5, "matrix": [5, 4] },
+
+ {"x": 16, "y": 5, "matrix": [5, 14] },
+ {"x": 17, "y": 5, "matrix": [5, 15] },
+ {"x": 18, "y": 5, "matrix": [5, 16] },
+ {"x": 19, "y": 5, "matrix": [5, 17] },
+
+ {"x": 5, "y": 7, "matrix": [4, 6] },
+ {"x": 6, "y": 7, "matrix": [4, 7] },
+ {"x": 7, "y": 7, "matrix": [4, 8] },
+
+ {"x": 13, "y": 7, "matrix": [4, 10] },
+ {"x": 14, "y": 7, "matrix": [4, 11] },
+ {"x": 15, "y": 7, "matrix": [4, 12] },
+
+ {"x": 5, "y": 8, "h": 2, "matrix": [5, 6] },
+ {"x": 6, "y": 8, "h": 2, "matrix": [5, 7] },
+ {"x": 7, "y": 8, "matrix": [5, 8] },
+
+ {"x": 13, "y": 8, "matrix": [5, 10] },
+ {"x": 14, "y": 8, "h": 2, "matrix": [5, 11] },
+ {"x": 15, "y": 8, "h": 2, "matrix": [5, 12] },
+
+ {"x": 7, "y": 9, "matrix": [6, 8] },
+ {"x": 13, "y": 9, "matrix": [6, 10] }
+ ]
+ }
+ }
+}
diff --git a/keyboards/handwired/dqz11n1g/keymaps/default/keymap.c b/keyboards/handwired/dqz11n1g/keymaps/default/keymap.c
new file mode 100644
index 0000000000..29d9cad7b7
--- /dev/null
+++ b/keyboards/handwired/dqz11n1g/keymaps/default/keymap.c
@@ -0,0 +1,72 @@
+/* Copyright (c) 2022 David Kuehling < dvdkhlng TA posteo TOD de >
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#include QMK_KEYBOARD_H
+
+enum layer_names { _DEFAULT, _FUNCTION };
+#define KC_FUN TG(_FUNCTION)
+
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+ [_DEFAULT] = LAYOUT(
+ KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_FUN, KC_NUM, KC_P7, KC_P8, KC_P9, KC_PSLS, KC_PSCR, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12,
+
+ KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_VOLU, KC_ESC, KC_P4, KC_P5, KC_P6, KC_PAST, KC_SCRL, KC_7, KC_8, KC_9, KC_0, KC_MINS,KC_EQL,
+ KC_NUBS,KC_Q, KC_W, KC_E, KC_R, KC_T, KC_VOLD, KC_GRV, KC_P1, KC_P2, KC_P3, KC_PMNS, KC_BRK, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC,
+ KC_CAPS,KC_A, KC_S, KC_D, KC_F, KC_G, KC_MUTE, KC_WSCH,KC_P0,KC_PDOT,KC_PENT,KC_PPLS,KC_INS, KC_H, KC_J, KC_K, KC_L, KC_SCLN,KC_QUOT,
+ KC_LSFT,KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM,KC_DOT, KC_SLSH,KC_RSFT,
+ /* */ KC_LCTL, KC_LGUI,KC_LALT,KC_RBRC, KC_NUHS,KC_RALT,KC_APP, KC_RCTL, /* */
+
+ /* thumb keys: */ KC_BSPC, KC_HOME, KC_END, KC_LEFT, KC_RGHT, KC_DEL,
+ /* thumb keys: */ KC_SPC, KC_TAB, KC_PGUP, KC_UP, KC_ENT, KC_SPC,
+ /* thumb keys: */ KC_PGDN, KC_DOWN
+ ),
+
+ /* This is the "function key locked" layer. It is not documented by
+ * Maltron, so just putting some "Quantum" keycodes here for testing that
+ * the layer exists and Fun Lock LED works. */
+ [_FUNCTION] = LAYOUT(
+ KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_TRNS,KC_TRNS,KC_BTN3,KC_MS_U,KC_WH_U,KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
+
+ KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, CK_UP, AU_ON, KC_MS_L,KC_BTN1,KC_MS_R,KC_NO, KC_TRNS, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
+ KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, CK_DOWN,AU_OFF, KC_BTN2,KC_MS_D,KC_WH_D,KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
+ KC_TRNS,KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, CK_TOGG,KC_NO, KC_ACL0,KC_ACL1,KC_ACL2,KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
+ KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
+ /* */ KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, /* */
+
+ /* thumb keys: */ KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
+ /* thumb keys: */ KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO,
+ /* thumb keys: */ KC_NO, KC_NO
+ )
+};
+
+/* Show "Fun Lock" layer state via the "Fun Lock" LED */
+layer_state_t layer_state_set_user(layer_state_t state) {
+
+ setPinOutput(LED_FUN_LOCK_PIN);
+
+ if (layer_state_cmp(state, _FUNCTION))
+ writePinHigh(LED_FUN_LOCK_PIN);
+ else
+ writePinLow(LED_FUN_LOCK_PIN);
+
+ return state;
+}
+
+/*
+ * Local Variables:
+ * c-basic-offset:4
+ * fill-column: 76
+ * End:
+ */
diff --git a/keyboards/handwired/dqz11n1g/keymaps/default/readme.md b/keyboards/handwired/dqz11n1g/keymaps/default/readme.md
new file mode 100644
index 0000000000..d61546eb37
--- /dev/null
+++ b/keyboards/handwired/dqz11n1g/keymaps/default/readme.md
@@ -0,0 +1,17 @@
+![DQz11N1G-DE Layout Image](https://u.cubeupload.com/ddklg/OPBN5q.jpg)
+
+# Default Layout for DQz11N1G-DE
+
+This is the layout corresponding to what the Maltron keyboard DQz11N1G-DE I
+own came with (using the original pre-installed controller). Note that this
+differs from German Maltron layout as published on [Maltron's
+website](https://www.maltron.com/germany.html). Use the photo above as a
+reference for the layout implemented here.
+
+I did not find any official documentation about the the Function Lock key on
+the original Maltron keyboards. It seems that it implements some of the
+features that are documented for the one-handed Maltron keyboards. Most
+keys don't send any keycodes at all when function lock is enabed.
+
+We instead map some of the Quantum keycodes (mouse keys and audio control)
+in the middle (keypad) section of the keypad, when Function Lock is enabled. \ No newline at end of file
diff --git a/keyboards/handwired/dqz11n1g/matrix.c b/keyboards/handwired/dqz11n1g/matrix.c
new file mode 100644
index 0000000000..f9f3f2b68f
--- /dev/null
+++ b/keyboards/handwired/dqz11n1g/matrix.c
@@ -0,0 +1,131 @@
+/*
+ Copyright (c) 2022 David Kuehling <dvdkhlng TA posteo TOD de>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <avr/io.h>
+
+#include "spi_master.h"
+#include "quantum.h"
+#include "matrix.h"
+
+static pin_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
+
+static void unselect_rows(void);
+
+void matrix_init_custom(void) {
+ /* initialize row pins */
+ for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
+ setPinOutput(row_pins[row]);
+ }
+ unselect_rows();
+
+ /* columns read via shift-register on SPI lines */
+
+ /* Enable SPI, Master, set clock rate fck/2. First bit already at Qh
+ * output before clock edge (CPHA=0). SN74HC165 shift register shifts
+ * on low-to-high transition (CPOL=1). Receive the LSB first (DORD=1).
+ */
+ bool lsbFirst = true;
+ uint8_t mode = 2; /* CPOL=1, CPHA=0 */
+ uint16_t divisor = 16;
+
+ /* According to Atmega32U4 datasheet, PB0 *must* be set to output,
+ * otherwise it will interfere with SPI master operation. On pro-micro
+ * it's connected to a yellew LED. */
+ pin_t slavePin = PB0;
+ spi_init();
+ spi_start(slavePin, lsbFirst, mode, divisor);
+
+ /* Initialize pin controlling the shift register's SH/~LD pin */
+ setPinOutput(ROW_SHIFT_PIN);
+}
+
+static void select_row(uint8_t row) {
+ pin_t pin = row_pins[row];
+ if (pin != NO_PIN) {
+ writePinHigh(pin);
+ }
+}
+
+static void unselect_row(uint8_t row) {
+ pin_t pin = row_pins[row];
+ if (pin != NO_PIN) {
+ writePinLow(pin);
+ }
+}
+
+static void unselect_rows(void) {
+ for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
+ unselect_row(row);
+ }
+}
+
+bool matrix_read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) {
+ /* Start with a clear matrix row */
+ matrix_row_t current_row_value = 0;
+
+ /* Set shift register SH/~LD pin to "load" mode */
+ writePinLow(ROW_SHIFT_PIN);
+ select_row(current_row);
+ matrix_output_select_delay();
+
+ /* Set shift register SH/~LD pin to "shift" mode */
+ writePinHigh(ROW_SHIFT_PIN);
+
+ /* For each octet of columns... */
+ for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index += 8) {
+ spi_status_t read_result = spi_read();
+ if (read_result >= 0) {
+ /* only if SPI read successful: populate the matrix row with the
+ state of the 8 consecutive column bits */
+ current_row_value |= ((matrix_row_t)read_result << col_index);
+ }
+ }
+
+ /* Unselect row & wait for all columns signals to go high. */
+ unselect_row(current_row);
+ matrix_output_unselect_delay(current_row, current_row_value != 0);
+
+ /* Update row in matrix. */
+ if (current_row_value != current_matrix[current_row]) {
+ current_matrix[current_row] = current_row_value;
+ return true;
+ }
+
+ return false;
+}
+
+bool matrix_scan_custom(matrix_row_t curr_matrix[]) {
+ bool changed = false;
+
+ /* set row, read cols */
+ for (uint8_t current_row = 0; current_row < MATRIX_ROWS; current_row++) {
+ changed |= matrix_read_cols_on_row(curr_matrix, current_row);
+ }
+
+ return changed;
+}
+
+/*
+ * Local Variables:
+ * c-basic-offset:4
+ * fill-column: 76
+ * End:
+ */
diff --git a/keyboards/handwired/dqz11n1g/readme.md b/keyboards/handwired/dqz11n1g/readme.md
new file mode 100644
index 0000000000..0e3a57873d
--- /dev/null
+++ b/keyboards/handwired/dqz11n1g/readme.md
@@ -0,0 +1,80 @@
+# DQz11N1G
+
+![DQz11N1G](https://u.cubeupload.com/ddklg/OPBN5q.jpg)
+
+Firmware for a DIY controller replacement for one of the ortholinear contoured
+keyboards manufactured by [PCD Maltron Ltd](https://www.maltron.com)
+
+This work here in no way officially associated with PCD Maltron Ltd and comes
+with NO WARRANTY. Modifying your Maltron keyboard as described below will
+certainly void your warranty and may cause damage to your keyboard. Proceed
+at your own risk!
+
+* maintainer: [David Kuehling](https://github.com/dvdkhlng/qmk_firmware_dqz11n1g)
+* Hardware Supported: Maltron DQz11N1G with a replacement controller board
+ assembled as described below. The work here is based on a german version
+ of the keyboard: DQz11N1G-DE. I assume, but don't know for sure, that
+ minor or no changes at all are required to make this work on different
+ language versions of the keyboard.
+* Hardware Availability:
+ * [PCD Maltron Ltd](https://www.maltron.com), for the original keyboard
+ * 1x [Arduino Pro Micro](https://www.sparkfun.com/products/12640)
+ * 3x [SN74HC165](https://www.ti.com/product/SN74HC165)
+ * 1x DIL connector 2 rows a 17 pins.
+ * 19x pull-down resistors (10k Ohm),
+ * 4 LED current limiting resistors (not sure about the correct resistance,
+ using 470 Ohm here)
+
+Make example for this keyboard (after setting up your build environment):
+
+ make handwired/dqz11n1g:default
+
+## In Detail
+
+[PCD Maltron Ltd](https://www.maltron.com) manufacturs ergonomic keyboards
+that appear to be hand-wired internally. For the Maltron DQz11N1G-DE
+keyboard that I happen to own, the keyboard matrix is wired to a 34-pin DIL
+connector. This makes it rather easy to replace the proprietary
+controller-board with a self-made board based on the QMK firmware.
+
+I don't really like the default layout of my Maltron DQz11N1G-DE keyboard,
+and modding it to work with QMK allows me to adapt it to my needs. It
+especially allows for the two space keys to assume different roles, thereby
+creating an additional easily reachable thumb-key.
+
+### Internal Details of Keyboard Matrix and DIL Connector
+
+![DQz11N1G-DE keyboard matrix](https://u.cubeupload.com/ddklg/OJFue6.jpg)
+
+![DQz11N1G-DE keyboard matrix connector](https://u.cubeupload.com/ddklg/fjFXeL.png)
+
+### Replacement Keyboard Controller Board
+
+Due to supply chain problems, I decided to base this on an
+Arduino-compatible [Pro Micro](https://www.sparkfun.com/products/12640)
+board which is still easy to source.
+
+Unfortunately pin-count of the DQz11N1G-DE's keyboard matrix is way beyond
+the Pro Micro's available I/O pin count. I'm using three 8-bit
+shift-registers ([SN74HC165](https://www.ti.com/product/SN74HC165) ) to
+connect the 19 colums of the keyboard matrix for readout. Due to diode
+direction in DQz11N1G-DE we also need 19 pull-down resistors one for each of
+the utilized shift-register inputs.
+
+This is a design sketch of the replacement board this is based on. Note how
+we need a custom matrix.c source file to deal with the shift register based
+keyboard readout.
+
+![Sketch of Keyboard Controller Board](https://u.cubeupload.com/ddklg/GBZgSf.png)
+
+This is how the assembled controller board looks like, on the right side you
+see the original PIC-based controller the keyboard ships with.
+
+![The assembled controller next to the original controller the keyboard ships with](https://u.cubeupload.com/ddklg/KLYF2V.jpg)
+
+Inside of the keyboard after installing the new controller board:
+
+![Installed controller](https://u.cubeupload.com/ddklg/Br0aiF.jpg)
+
+(Not visible in the photo: I drilled hole into the keyboard above the USB
+connector for a reset switch to simplify flashing controller firmware)
diff --git a/keyboards/handwired/dqz11n1g/rules.mk b/keyboards/handwired/dqz11n1g/rules.mk
new file mode 100644
index 0000000000..db8a809da9
--- /dev/null
+++ b/keyboards/handwired/dqz11n1g/rules.mk
@@ -0,0 +1,24 @@
+# MCU name
+MCU = atmega32u4
+
+# Bootloader selection
+BOOTLOADER = caterina
+
+# Keyboard matrix uses shift-registers read via SPI
+CUSTOM_MATRIX = lite
+SRC += matrix.c
+QUANTUM_LIB_SRC += spi_master.c
+
+# Build Options
+# change yes to no to disable
+#
+BOOTMAGIC_ENABLE = no # Enable Bootmagic Lite
+MOUSEKEY_ENABLE = yes # Mouse keys
+EXTRAKEY_ENABLE = yes # Audio control and System control
+CONSOLE_ENABLE = no # Console for debug
+COMMAND_ENABLE = yes # Commands for debug and configuration
+NKRO_ENABLE = no # Enable N-Key Rollover
+BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality
+RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow
+AUDIO_ENABLE = yes # Audio output
+