diff --git a/keyboards/aki27/cocot46plus/cocot46plus.c b/keyboards/aki27/cocot46plus/cocot46plus.c
new file mode 100644
index 000000000000..4becf2f1024a
--- /dev/null
+++ b/keyboards/aki27/cocot46plus/cocot46plus.c
@@ -0,0 +1,289 @@
+/*
+Copyright 2022 aki27
+
+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 .
+*/
+
+#include QMK_KEYBOARD_H
+#include
+
+// Invert vertical scroll direction
+#ifndef COCOT_SCROLL_INV_DEFAULT
+# define COCOT_SCROLL_INV_DEFAULT 1
+#endif
+
+// All the default values here refer to O-based array indexes
+// not actual values
+
+#ifndef COCOT_CPI_OPTIONS
+# define COCOT_CPI_OPTIONS { 250, 500, 750, 1000, 1250 }
+#endif
+#ifndef COCOT_CPI_DEFAULT
+# define COCOT_CPI_DEFAULT 4
+#endif
+
+#ifndef COCOT_SCROLL_DIVIDERS
+# define COCOT_SCROLL_DIVIDERS { 1, 2, 3, 4, 5, 6 }
+#endif
+#ifndef COCOT_SCROLL_DIV_DEFAULT
+# define COCOT_SCROLL_DIV_DEFAULT 4
+#endif
+
+
+#ifndef COCOT_ROTATION_ANGLE
+# define COCOT_ROTATION_ANGLE { -60, -45, -30, -15, 0, 15, 30, 45, 60 }
+#endif
+#ifndef COCOT_ROTATION_DEFAULT
+# define COCOT_ROTATION_DEFAULT 2
+#endif
+
+
+cocot_config_t cocot_config;
+uint16_t cpi_array[] = COCOT_CPI_OPTIONS;
+uint16_t scrl_div_array[] = COCOT_SCROLL_DIVIDERS;
+int8_t angle_array[] = COCOT_ROTATION_ANGLE;
+#define CPI_OPTION_SIZE (sizeof(cpi_array) / sizeof(uint16_t))
+#define SCRL_DIV_SIZE (sizeof(scrl_div_array) / sizeof(uint16_t))
+#define ANGLE_SIZE (sizeof(angle_array) / sizeof(int8_t))
+
+
+// Trackball State
+bool BurstState = false; // init burst state for Trackball module
+uint16_t MotionStart = 0; // Timer for accel, 0 is resting state
+
+// Scroll Accumulation
+static int16_t h_acm = 0;
+static int16_t v_acm = 0;
+
+
+void pointing_device_init_kb(void) {
+ // set the CPI.
+ pointing_device_set_cpi(cpi_array[cocot_config.cpi_idx]);
+ adns5050_write_reg(0x22, 0b10000 | 0x80);
+}
+
+report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) {
+
+ double rad = (double)angle_array[cocot_config.rotation_angle] * (M_PI / 180) * -1;
+ int8_t x_rev = + mouse_report.x * cos(rad) - mouse_report.y * sin(rad);
+ int8_t y_rev = + mouse_report.x * sin(rad) + mouse_report.y * cos(rad);
+
+ if (cocot_get_scroll_mode()) {
+ // rock scroll direction
+ if (abs(x_rev) > abs(y_rev)) {
+ y_rev = 0;
+ } else {
+ x_rev = 0;
+ }
+
+ // accumulate scroll
+ h_acm += x_rev * cocot_config.scrl_inv;
+ v_acm += y_rev * cocot_config.scrl_inv * -1;
+
+ int8_t h_rev = h_acm >> scrl_div_array[cocot_config.scrl_div];
+ int8_t v_rev = v_acm >> scrl_div_array[cocot_config.scrl_div];
+
+ // clear accumulated scroll on assignment
+
+ if (h_rev != 0) {
+ if (mouse_report.h + h_rev > 127) {
+ h_rev = 127 - mouse_report.h;
+ } else if (mouse_report.h + h_rev < -127) {
+ h_rev = -127 - mouse_report.h;
+ }
+ mouse_report.h += h_rev;
+ h_acm -= h_rev << scrl_div_array[cocot_config.scrl_div];
+ }
+ if (v_rev != 0) {
+ if (mouse_report.v + v_rev > 127) {
+ v_rev = 127 - mouse_report.v;
+ } else if (mouse_report.v + v_rev < -127) {
+ v_rev = -127 - mouse_report.v;
+ }
+ mouse_report.v += v_rev;
+ v_acm -= v_rev << scrl_div_array[cocot_config.scrl_div];
+ }
+
+ mouse_report.x = 0;
+ mouse_report.y = 0;
+ } else {
+ mouse_report.x = x_rev;
+ mouse_report.y = y_rev;
+ }
+
+ return pointing_device_task_user(mouse_report);
+}
+
+bool process_record_kb(uint16_t keycode, keyrecord_t* record) {
+ // xprintf("KL: kc: %u, col: %u, row: %u, pressed: %u\n", keycode, record->event.key.col, record->event.key.row, record->event.pressed);
+
+ if (!process_record_user(keycode, record)) {
+ return false;
+ }
+
+ if (keycode == CPI_SW && record->event.pressed) {
+ cocot_config.cpi_idx = (cocot_config.cpi_idx + 1) % CPI_OPTION_SIZE;
+ eeconfig_update_kb(cocot_config.raw);
+ pointing_device_set_cpi(cpi_array[cocot_config.cpi_idx]);
+ }
+
+ if (keycode == SCRL_SW && record->event.pressed) {
+ cocot_config.scrl_div = (cocot_config.scrl_div + 1) % SCRL_DIV_SIZE;
+ eeconfig_update_kb(cocot_config.raw);
+ }
+
+ if (keycode == ROT_R15 && record->event.pressed) {
+ cocot_config.rotation_angle = (cocot_config.rotation_angle + 1) % ANGLE_SIZE;
+ eeconfig_update_kb(cocot_config.raw);
+ }
+
+ if (keycode == ROT_L15 && record->event.pressed) {
+ cocot_config.rotation_angle = (ANGLE_SIZE + cocot_config.rotation_angle - 1) % ANGLE_SIZE;
+ eeconfig_update_kb(cocot_config.raw);
+ }
+
+ if (keycode == SCRL_IN && record->event.pressed) {
+ cocot_config.scrl_inv = -cocot_config.scrl_inv;
+ eeconfig_update_kb(cocot_config.raw);
+ }
+
+ if (keycode == SCRL_TO && record->event.pressed) {
+ {
+ cocot_config.scrl_mode ^= 1;
+ }
+ }
+
+ if (keycode == SCRL_MO) {
+ {
+ cocot_config.scrl_mode ^= 1;
+ }
+ }
+
+ return true;
+}
+
+void eeconfig_init_kb(void) {
+ cocot_config.cpi_idx = COCOT_CPI_DEFAULT;
+ cocot_config.scrl_div = COCOT_SCROLL_DIV_DEFAULT;
+ cocot_config.rotation_angle = COCOT_ROTATION_DEFAULT;
+ cocot_config.scrl_inv = COCOT_SCROLL_INV_DEFAULT;
+ cocot_config.scrl_mode = false;
+ eeconfig_update_kb(cocot_config.raw);
+ eeconfig_init_user();
+ adns5050_write_reg(0x22, 0b10000 | 0x80);
+}
+
+
+void matrix_init_kb(void) {
+ // is safe to just read CPI setting since matrix init
+ // comes before pointing device init.
+ cocot_config.raw = eeconfig_read_kb();
+ if (cocot_config.cpi_idx > CPI_OPTION_SIZE) // || cocot_config.scrl_div > SCRL_DIV_SIZE || cocot_config.rotation_angle > ANGLE_SIZE)
+ {
+ eeconfig_init_kb();
+ }
+ matrix_init_user();
+}
+
+
+bool cocot_get_scroll_mode(void) {
+ return cocot_config.scrl_mode;
+}
+
+void cocot_set_scroll_mode(bool mode) {
+ cocot_config.scrl_mode = mode;
+}
+
+
+
+// OLED utility
+#ifdef OLED_ENABLE
+
+bool oled_task_kb(void) {
+ if (!oled_task_user()) {
+ return false;
+ }
+ render_logo();
+ oled_write_layer_state();
+ return false;
+}
+
+oled_rotation_t oled_init_kb(oled_rotation_t rotation) {
+ return OLED_ROTATION_0;
+}
+
+static const char PROGMEM cocot_logo[] = {
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94,
+ 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4,
+ 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4,
+ 0};
+
+void render_logo(void) {
+ oled_write_P(cocot_logo, false);
+};
+
+void oled_write_layer_state(void) {
+
+ oled_write_P(PSTR(" "), false);
+
+ switch (get_highest_layer(layer_state | default_layer_state)) {
+ case 0:
+ oled_write_P(PSTR("Base "), false);
+ break;
+ case 1:
+ oled_write_P(PSTR("Lower"), false);
+ break;
+ case 2:
+ oled_write_P(PSTR("Raise"), false);
+ break;
+ case 3:
+ oled_write_P(PSTR("Mouse"), false);
+ break;
+ case 4:
+ oled_write_P(PSTR("L4 "), false);
+ break;
+ case 5:
+ oled_write_P(PSTR("L5 "), false);
+ break;
+ case 6:
+ oled_write_P(PSTR("L6 "), false);
+ break;
+ default:
+ oled_write_P(PSTR("Undef"), false);
+ break;
+ }
+ oled_write_P(PSTR("/"), false);
+ if (cocot_get_scroll_mode()){
+ oled_write_P(PSTR("S"), false);
+ } else{
+ oled_write_P(PSTR("C"), false);
+ }
+
+ char cpi[5];
+ char scroll_div[3];
+ char angle[4];
+ snprintf(cpi, 5, "%4d", cpi_array[cocot_config.cpi_idx]);
+ snprintf(scroll_div, 3, "%2d", scrl_div_array[cocot_config.scrl_div]);
+ snprintf(angle, 4, "%3d", angle_array[cocot_config.rotation_angle]);
+
+ oled_write_P(PSTR("/"), false);
+ oled_write(cpi, false);
+ oled_write_P(PSTR("/"), false);
+ oled_write(scroll_div, false);
+ oled_write_P(PSTR("/"), false);
+ oled_write(angle, false);
+}
+
+#endif
+
diff --git a/keyboards/aki27/cocot46plus/cocot46plus.h b/keyboards/aki27/cocot46plus/cocot46plus.h
new file mode 100644
index 000000000000..dba6ac69d9b6
--- /dev/null
+++ b/keyboards/aki27/cocot46plus/cocot46plus.h
@@ -0,0 +1,41 @@
+/*
+Copyright 2022 aki27
+
+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 .
+*/
+
+#pragma once
+
+#include "quantum.h"
+
+typedef union {
+ uint32_t raw;
+ struct {
+ uint8_t cpi_idx;
+ uint8_t scrl_div;
+ uint8_t rotation_angle;
+ int8_t scrl_inv;
+ bool scrl_mode;
+ report_mouse_t last_mouse;
+ };
+} cocot_config_t;
+
+extern cocot_config_t cocot_config;
+
+
+bool cocot_get_scroll_mode(void);
+void cocot_set_scroll_mode(bool mode);
+
+void render_logo(void);
+void oled_write_layer_state(void);
diff --git a/keyboards/aki27/cocot46plus/config.h b/keyboards/aki27/cocot46plus/config.h
new file mode 100644
index 000000000000..357f5e14765c
--- /dev/null
+++ b/keyboards/aki27/cocot46plus/config.h
@@ -0,0 +1,33 @@
+/*
+Copyright 2022 aki27
+
+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 .
+*/
+
+#pragma once
+
+// These do not seem to have keyboard.json support yet.
+#define ADNS5050_SCLK_PIN GP23
+#define ADNS5050_SDIO_PIN GP8
+#define ADNS5050_CS_PIN GP9
+
+#define I2C1_SDA_PIN GP2
+#define I2C1_SCL_PIN GP3
+
+/* key matrix size */
+#define MATRIX_ROWS 10
+#define MATRIX_COLS 6
+
+#define POINTING_DEVICE_ROTATION_180
+#define OLED_FONT_H "keyboards/aki27/cocot46plus/glcdfont.c"
diff --git a/keyboards/aki27/cocot46plus/glcdfont.c b/keyboards/aki27/cocot46plus/glcdfont.c
new file mode 100644
index 000000000000..bd7d8bae003c
--- /dev/null
+++ b/keyboards/aki27/cocot46plus/glcdfont.c
@@ -0,0 +1,232 @@
+// This is the 'classic' fixed-space bitmap font for Adafruit_GFX since 1.0.
+// See gfxfont.h for newer custom bitmap font info.
+
+#include "progmem.h"
+
+// Standard ASCII 5x7 font
+const unsigned char font[] PROGMEM = {
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x3E, 0x5B, 0x4F, 0x5B, 0x3E, 0x00,
+0x3E, 0x6B, 0x4F, 0x6B, 0x3E, 0x00,
+0x1C, 0x3E, 0x7C, 0x3E, 0x1C, 0x00,
+0x18, 0x3C, 0x7E, 0x3C, 0x18, 0x00,
+0x1C, 0x57, 0x7D, 0x57, 0x1C, 0x00,
+0x1C, 0x5E, 0x7F, 0x5E, 0x1C, 0x00,
+0x00, 0x18, 0x3C, 0x18, 0x00, 0x00,
+0xFF, 0xE7, 0xC3, 0xE7, 0xFF, 0x00,
+0x00, 0x18, 0x24, 0x18, 0x00, 0x00,
+0xFF, 0xE7, 0xDB, 0xE7, 0xFF, 0x00,
+0x30, 0x48, 0x3A, 0x06, 0x0E, 0x00,
+0x26, 0x29, 0x79, 0x29, 0x26, 0x00,
+0x40, 0x7F, 0x05, 0x05, 0x07, 0x00,
+0x40, 0x7F, 0x05, 0x25, 0x3F, 0x00,
+0x5A, 0x3C, 0xE7, 0x3C, 0x5A, 0x00,
+0x7F, 0x3E, 0x1C, 0x1C, 0x08, 0x00,
+0x08, 0x1C, 0x1C, 0x3E, 0x7F, 0x00,
+0x14, 0x22, 0x7F, 0x22, 0x14, 0x00,
+0x5F, 0x5F, 0x00, 0x5F, 0x5F, 0x00,
+0x06, 0x09, 0x7F, 0x01, 0x7F, 0x00,
+0x00, 0x66, 0x89, 0x95, 0x6A, 0x00,
+0x60, 0x60, 0x60, 0x60, 0x60, 0x00,
+0x94, 0xA2, 0xFF, 0xA2, 0x94, 0x00,
+0x08, 0x04, 0x7E, 0x04, 0x08, 0x00,
+0x10, 0x20, 0x7E, 0x20, 0x10, 0x00,
+0x08, 0x08, 0x2A, 0x1C, 0x08, 0x00,
+0x08, 0x1C, 0x2A, 0x08, 0x08, 0x00,
+0x1E, 0x10, 0x10, 0x10, 0x10, 0x00,
+0x0C, 0x1E, 0x0C, 0x1E, 0x0C, 0x00,
+0x30, 0x38, 0x3E, 0x38, 0x30, 0x00,
+0x06, 0x0E, 0x3E, 0x0E, 0x06, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x5F, 0x00, 0x00, 0x00,
+0x00, 0x07, 0x00, 0x07, 0x00, 0x00,
+0x14, 0x7F, 0x14, 0x7F, 0x14, 0x00,
+0x24, 0x2A, 0x7F, 0x2A, 0x12, 0x00,
+0x23, 0x13, 0x08, 0x64, 0x62, 0x00,
+0x36, 0x49, 0x56, 0x20, 0x50, 0x00,
+0x00, 0x08, 0x07, 0x03, 0x00, 0x00,
+0x00, 0x1C, 0x22, 0x41, 0x00, 0x00,
+0x00, 0x41, 0x22, 0x1C, 0x00, 0x00,
+0x2A, 0x1C, 0x7F, 0x1C, 0x2A, 0x00,
+0x08, 0x08, 0x3E, 0x08, 0x08, 0x00,
+0x00, 0x80, 0x70, 0x30, 0x00, 0x00,
+0x08, 0x08, 0x08, 0x08, 0x08, 0x00,
+0x00, 0x00, 0x60, 0x60, 0x00, 0x00,
+0x20, 0x10, 0x08, 0x04, 0x02, 0x00,
+0x3E, 0x51, 0x49, 0x45, 0x3E, 0x00,
+0x00, 0x42, 0x7F, 0x40, 0x00, 0x00,
+0x72, 0x49, 0x49, 0x49, 0x46, 0x00,
+0x21, 0x41, 0x49, 0x4D, 0x33, 0x00,
+0x18, 0x14, 0x12, 0x7F, 0x10, 0x00,
+0x27, 0x45, 0x45, 0x45, 0x39, 0x00,
+0x3C, 0x4A, 0x49, 0x49, 0x31, 0x00,
+0x41, 0x21, 0x11, 0x09, 0x07, 0x00,
+0x36, 0x49, 0x49, 0x49, 0x36, 0x00,
+0x46, 0x49, 0x49, 0x29, 0x1E, 0x00,
+0x00, 0x00, 0x14, 0x00, 0x00, 0x00,
+0x00, 0x40, 0x34, 0x00, 0x00, 0x00,
+0x00, 0x08, 0x14, 0x22, 0x41, 0x00,
+0x14, 0x14, 0x14, 0x14, 0x14, 0x00,
+0x00, 0x41, 0x22, 0x14, 0x08, 0x00,
+0x02, 0x01, 0x59, 0x09, 0x06, 0x00,
+0x3E, 0x41, 0x5D, 0x59, 0x4E, 0x00,
+0x7C, 0x12, 0x11, 0x12, 0x7C, 0x00,
+0x7F, 0x49, 0x49, 0x49, 0x36, 0x00,
+0x3E, 0x41, 0x41, 0x41, 0x22, 0x00,
+0x7F, 0x41, 0x41, 0x41, 0x3E, 0x00,
+0x7F, 0x49, 0x49, 0x49, 0x41, 0x00,
+0x7F, 0x09, 0x09, 0x09, 0x01, 0x00,
+0x3E, 0x41, 0x41, 0x51, 0x73, 0x00,
+0x7F, 0x08, 0x08, 0x08, 0x7F, 0x00,
+0x00, 0x41, 0x7F, 0x41, 0x00, 0x00,
+0x20, 0x40, 0x41, 0x3F, 0x01, 0x00,
+0x7F, 0x08, 0x14, 0x22, 0x41, 0x00,
+0x7F, 0x40, 0x40, 0x40, 0x40, 0x00,
+0x7F, 0x02, 0x1C, 0x02, 0x7F, 0x00,
+0x7F, 0x04, 0x08, 0x10, 0x7F, 0x00,
+0x3E, 0x41, 0x41, 0x41, 0x3E, 0x00,
+0x7F, 0x09, 0x09, 0x09, 0x06, 0x00,
+0x3E, 0x41, 0x51, 0x21, 0x5E, 0x00,
+0x7F, 0x09, 0x19, 0x29, 0x46, 0x00,
+0x26, 0x49, 0x49, 0x49, 0x32, 0x00,
+0x03, 0x01, 0x7F, 0x01, 0x03, 0x00,
+0x3F, 0x40, 0x40, 0x40, 0x3F, 0x00,
+0x1F, 0x20, 0x40, 0x20, 0x1F, 0x00,
+0x3F, 0x40, 0x38, 0x40, 0x3F, 0x00,
+0x63, 0x14, 0x08, 0x14, 0x63, 0x00,
+0x03, 0x04, 0x78, 0x04, 0x03, 0x00,
+0x61, 0x59, 0x49, 0x4D, 0x43, 0x00,
+0x00, 0x7F, 0x41, 0x41, 0x41, 0x00,
+0x02, 0x04, 0x08, 0x10, 0x20, 0x00,
+0x00, 0x41, 0x41, 0x41, 0x7F, 0x00,
+0x04, 0x02, 0x01, 0x02, 0x04, 0x00,
+0x40, 0x40, 0x40, 0x40, 0x40, 0x00,
+0x00, 0x03, 0x07, 0x08, 0x00, 0x00,
+0x20, 0x54, 0x54, 0x78, 0x40, 0x00,
+0x7F, 0x28, 0x44, 0x44, 0x38, 0x00,
+0x38, 0x44, 0x44, 0x44, 0x28, 0x00,
+0x38, 0x44, 0x44, 0x28, 0x7F, 0x00,
+0x38, 0x54, 0x54, 0x54, 0x18, 0x00,
+0x00, 0x08, 0x7E, 0x09, 0x02, 0x00,
+0x18, 0x24, 0x24, 0x1C, 0x78, 0x00,
+0x7F, 0x08, 0x04, 0x04, 0x78, 0x00,
+0x00, 0x44, 0x7D, 0x40, 0x00, 0x00,
+0x20, 0x40, 0x40, 0x3D, 0x00, 0x00,
+0x7F, 0x10, 0x28, 0x44, 0x00, 0x00,
+0x00, 0x41, 0x7F, 0x40, 0x00, 0x00,
+0x7C, 0x04, 0x78, 0x04, 0x78, 0x00,
+0x7C, 0x08, 0x04, 0x04, 0x78, 0x00,
+0x38, 0x44, 0x44, 0x44, 0x38, 0x00,
+0x7C, 0x18, 0x24, 0x24, 0x18, 0x00,
+0x18, 0x24, 0x24, 0x18, 0x7C, 0x00,
+0x7C, 0x08, 0x04, 0x04, 0x08, 0x00,
+0x48, 0x54, 0x54, 0x54, 0x24, 0x00,
+0x04, 0x04, 0x3F, 0x44, 0x24, 0x00,
+0x3C, 0x40, 0x40, 0x20, 0x7C, 0x00,
+0x1C, 0x20, 0x40, 0x20, 0x1C, 0x00,
+0x3C, 0x40, 0x30, 0x40, 0x3C, 0x00,
+0x44, 0x28, 0x10, 0x28, 0x44, 0x00,
+0x4C, 0x90, 0x90, 0x90, 0x7C, 0x00,
+0x44, 0x64, 0x54, 0x4C, 0x44, 0x00,
+0x00, 0x08, 0x36, 0x41, 0x00, 0x00,
+0x00, 0x00, 0x77, 0x00, 0x00, 0x00,
+0x00, 0x41, 0x36, 0x08, 0x00, 0x00,
+0x02, 0x01, 0x02, 0x04, 0x02, 0x00,
+0x3C, 0x26, 0x23, 0x26, 0x3C, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0xC0, 0x60, 0xC0, 0xD0,
+0xC8, 0xE8, 0x6C, 0x64, 0x64, 0x64,
+0x6C, 0x68, 0x68, 0x98, 0xD0, 0x60,
+0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+0x80, 0x80, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x80, 0x80,
+0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x80, 0x80,
+0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x80, 0x80,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0xE0, 0xE0, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0xC0,
+0xE0, 0xE0, 0xE0, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x80, 0xE0, 0xE0,
+0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0xE0, 0xF0, 0xF0, 0xF0, 0xE0, 0xEC,
+0xEE, 0xF7, 0xF3, 0x70, 0x20, 0x00,
+0x7C, 0x7C, 0x7C, 0x7E, 0x00, 0x7E,
+0x7E, 0x7E, 0x7F, 0x7F, 0x7F, 0x00,
+0x00, 0x80, 0xC0, 0xE0, 0x7E, 0x5B,
+0x4F, 0x5B, 0xFE, 0xC0, 0x00, 0x00,
+0xC0, 0x00, 0xDC, 0xD7, 0xDE, 0xDE,
+0xDE, 0xD7, 0xDC, 0x00, 0xC0, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0xFC, 0x87, 0x78, 0xFE, 0xFE, 0x01,
+0x01, 0x78, 0x84, 0x82, 0x02, 0x02,
+0x86, 0x86, 0x03, 0x01, 0x87, 0xFF,
+0xFC, 0x03, 0xFE, 0x00, 0x00, 0x00,
+0x00, 0xFC, 0xFE, 0xCF, 0x03, 0x03,
+0x03, 0x03, 0x87, 0xC7, 0x86, 0x00,
+0x78, 0xFE, 0xFF, 0x87, 0x03, 0x03,
+0x03, 0x03, 0xCF, 0xFE, 0xFC, 0x00,
+0x38, 0xFE, 0xFF, 0x87, 0x03, 0x03,
+0x03, 0x03, 0xC7, 0x86, 0x84, 0x00,
+0xFC, 0xFE, 0x87, 0x03, 0x03, 0x03,
+0x03, 0x87, 0xFE, 0xFC, 0x30, 0x03,
+0x03, 0xFF, 0xFF, 0x83, 0x03, 0x00,
+0x00, 0x70, 0x78, 0x7E, 0x6F, 0x63,
+0x61, 0xFF, 0xFF, 0x60, 0x60, 0x00,
+0xF0, 0xFC, 0xFF, 0x0F, 0x0F, 0x0E,
+0x8E, 0xFC, 0xF8, 0x60, 0x00, 0x30,
+0x30, 0x30, 0x30, 0x30, 0xFF, 0xFF,
+0x30, 0x30, 0x30, 0x30, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x0F, 0x1F, 0x3F, 0x7F, 0x7F, 0x7F,
+0x7F, 0x7F, 0x3F, 0x1E, 0x0C, 0x00,
+0x1F, 0x1F, 0x1F, 0x3F, 0x00, 0x3F,
+0x3F, 0x3F, 0x7F, 0x7F, 0x7F, 0x00,
+0x30, 0x7B, 0x7F, 0x78, 0x30, 0x20,
+0x20, 0x30, 0x78, 0x7F, 0x3B, 0x00,
+0x03, 0x00, 0x0F, 0x7F, 0x0F, 0x0F,
+0x0F, 0x7F, 0x0F, 0x00, 0x03, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x03, 0x04, 0x19, 0x3F, 0x27,
+0x42, 0x58, 0x58, 0xD9, 0x99, 0x99,
+0xD8, 0x5D, 0x5F, 0x6E, 0x2C, 0x19,
+0x0C, 0x07, 0x01, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x01, 0x03, 0x03, 0x03,
+0x03, 0x03, 0x03, 0x03, 0x01, 0x00,
+0x00, 0x01, 0x01, 0x03, 0x03, 0x03,
+0x03, 0x03, 0x03, 0x01, 0x00, 0x00,
+0x00, 0x00, 0x01, 0x03, 0x03, 0x03,
+0x03, 0x03, 0x03, 0x01, 0x00, 0x00,
+0x00, 0x01, 0x03, 0x03, 0x03, 0x03,
+0x03, 0x03, 0x01, 0x00, 0x00, 0x00,
+0x00, 0x01, 0x03, 0x03, 0x03, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x03, 0x03, 0x00, 0x00, 0x00,
+0x00, 0x01, 0x03, 0x03, 0x03, 0x03,
+0x03, 0x03, 0x01, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x03, 0x03,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
diff --git a/keyboards/aki27/cocot46plus/keyboard.json b/keyboards/aki27/cocot46plus/keyboard.json
new file mode 100644
index 000000000000..9f3b89366af3
--- /dev/null
+++ b/keyboards/aki27/cocot46plus/keyboard.json
@@ -0,0 +1,130 @@
+{
+ "keyboard_name": "cocot46plus",
+ "manufacturer": "aki27",
+ "maintainer": "markstos",
+ "tags": ["unibody","ergo","corne","trackball","encoder","rgb"],
+ "usb": {
+ "device_version": "1.0.0",
+ "pid": "0x4600",
+ "vid": "0x4600"
+ },
+ "development_board": "promicro_rp2040",
+ "matrix_pins": {
+ "cols": ["GP29", "GP28", "GP27", "GP26", "GP22", "GP20"],
+ "rows": ["GP4", "GP5", "GP6", "GP7", "NO_PIN"]
+ },
+ "build": {
+ "lto": true
+ },
+ "features": {
+ "bootmagic": true,
+ "encoder": true,
+ "extrakey": true,
+ "mousekey": true,
+ "oled": true,
+ "pointing_device": true,
+ "rgblight": true
+ },
+ "ws2812": {
+ "pin": "GP21",
+ "driver": "vendor"
+ },
+ "encoder": {
+ "rotary": [
+ { "pin_a": "GP0", "pin_b": "GP1"}
+ ]
+ },
+ "rgblight": {
+ "led_count": 12,
+ "animations": {
+ "breathing": true,
+ "rainbow_mood": true,
+ "rainbow_swirl": true,
+ "snake": true,
+ "static_gradient": true,
+ "twinkle": true,
+ },
+ "hue_steps": 10,
+ "max_brightness": 120,
+ },
+ "keycodes":[
+ {"key": "CPI_SW"},
+ {"key": "SCRL_SW"},
+ {"key": "ROT_R15"},
+ {"key": "ROT_L15"},
+ {"key": "SCRL_MO"},
+ {"key": "SCRL_TO"},
+ {"key": "SCRL_IN"}
+ ],
+ "layouts": {
+ "LAYOUT": {
+ "layout": [
+ { "matrix": [0,0], "x": 0, "y": 0},
+ { "matrix": [0,1], "x": 1, "y": 0},
+ { "matrix": [0,2], "x": 2, "y": 0},
+ { "matrix": [0,3], "x": 3, "y": 0},
+ { "matrix": [0,4], "x": 4, "y": 0},
+ { "matrix": [0,5], "x": 5, "y": 0},
+
+ { "matrix": [5,5], "x": 9, "y": 0},
+ { "matrix": [5,4], "x": 10, "y": 0},
+ { "matrix": [5,3], "x": 11, "y": 0},
+ { "matrix": [5,2], "x": 12, "y": 0},
+ { "matrix": [5,1], "x": 13, "y": 0},
+ { "matrix": [5,0], "x": 14, "y": 0},
+
+
+ { "matrix": [1,0], "x": 0, "y": 1},
+ { "matrix": [1,1], "x": 1, "y": 1},
+ { "matrix": [1,2], "x": 2, "y": 1},
+ { "matrix": [1,3], "x": 3, "y": 1},
+ { "matrix": [1,4], "x": 4, "y": 1},
+ { "matrix": [1,5], "x": 5, "y": 1},
+
+ { "matrix": [6,5], "x": 9, "y": 1},
+ { "matrix": [6,4], "x": 10, "y": 1},
+ { "matrix": [6,3], "x": 11, "y": 1},
+ { "matrix": [6,2], "x": 12, "y": 1},
+ { "matrix": [6,1], "x": 13, "y": 1},
+ { "matrix": [6,0], "x": 14, "y": 1},
+
+
+ { "matrix": [2,0], "x": 0, "y": 2},
+ { "matrix": [2,1], "x": 1, "y": 2},
+ { "matrix": [2,2], "x": 2, "y": 2},
+ { "matrix": [2,3], "x": 3, "y": 2},
+ { "matrix": [2,4], "x": 4, "y": 2},
+ { "matrix": [2,5], "x": 5, "y": 2},
+
+ { "matrix": [7,5], "x": 9, "y": 2},
+ { "matrix": [7,4], "x": 10, "y": 2},
+ { "matrix": [7,3], "x": 11, "y": 2},
+ { "matrix": [7,2], "x": 12, "y": 2},
+ { "matrix": [7,1], "x": 13, "y": 2},
+ { "matrix": [7,0], "x": 14, "y": 2},
+
+
+ { "matrix": [3,0], "x": 2, "y": 3},
+ { "matrix": [3,1], "x": 3, "y": 3},
+ { "matrix": [3,2], "x": 4, "y": 3},
+ { "matrix": [3,3], "x": 5, "y": 3},
+
+ { "matrix": [3,5], "x": 6, "y": 3},
+ { "matrix": [8,5], "x": 8, "y": 3},
+
+ { "matrix": [8,3], "x": 9, "y": 3},
+ { "matrix": [8,2], "x": 10, "y": 3},
+ { "matrix": [8,1], "x": 11, "y": 3},
+ { "matrix": [8,0], "x": 12, "y": 3},
+
+ { "matrix": [4,2], "x": 6, "y": 4},
+ { "matrix": [3,4], "x": 7, "y": 4},
+ { "matrix": [4,4], "x": 8, "y": 4},
+
+ { "matrix": [9,2], "x": 9, "y": 4},
+ { "matrix": [8,4], "x": 10, "y": 4},
+ { "matrix": [9,5], "x": 11, "y": 4},
+ ]
+ }
+ }
+}
diff --git a/keyboards/aki27/cocot46plus/keymaps/default/keymap.c b/keyboards/aki27/cocot46plus/keymaps/default/keymap.c
new file mode 100644
index 000000000000..85b4e959bf6d
--- /dev/null
+++ b/keyboards/aki27/cocot46plus/keymaps/default/keymap.c
@@ -0,0 +1,125 @@
+/*
+Copyright 2022 aki27
+
+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 .
+*/
+
+#include QMK_KEYBOARD_H
+
+// Defines names for use in layer keycodes and the keymap
+enum layer_number {
+ _BASE,
+ _LOWER,
+ _RAISE,
+ _TRACKBALL
+};
+
+#define LW_MHEN LT(1,KC_INT5) // lower
+#define RS_HENK LT(2,KC_INT4) // raise
+#define DEL_ALT ALT_T(KC_DEL)
+
+// In the buttom row, KC_MS_BTN3 binds middle-click to the encoder's button press
+const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
+ [_BASE] = LAYOUT(
+ //|-------------------------------------------------------| |-------------------------------------------------------|
+ KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_BSPC,
+ //|-------------------------------------------------------| |-------------------------------------------------------|
+ KC_LCTL, KC_A, KC_S, KC_D, KC_F, KC_G, 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_MINS,
+ //|-------------------------------------------------------| |-------------------------------------------------------|
+ KC_LGUI, DEL_ALT, LW_MHEN, KC_SPC, KC_MS_BTN1, KC_MS_BTN2, KC_ENT, RS_HENK, KC_BSPC, KC_ESC,
+ XXXXXXX, KC_MS_BTN3, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX
+ //`--------------' `--------------'
+ ),
+ [_LOWER] = LAYOUT(
+ //|-------------------------------------------------------| |-------------------------------------------------------|
+ KC_ESC, KC_EXLM, KC_AT, KC_HASH, KC_DLR, KC_PERC, KC_CIRC, KC_AMPR, KC_ASTR, KC_LPRN, KC_RPRN, KC_BSPC,
+ //|-------------------------------------------------------| |-------------------------------------------------------|
+ KC_LCTL, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, KC_LCBR, KC_RCBR, KC_LBRC, KC_RBRC, KC_COLN, KC_DQUO,
+ //|-------------------------------------------------------| |-------------------------------------------------------|
+ KC_LSFT, KC_GRV, KC_TILD, KC_NUBS, KC_PIPE, XXXXXXX, KC_EQL, KC_PLUS, KC_LABK, KC_RABK, KC_QUES, KC_UNDS,
+ //|-------------------------------------------------------| |-------------------------------------------------------|
+ KC_LGUI, DEL_ALT, KC_TRNS, KC_SPC, KC_MS_BTN4, KC_MS_BTN5, KC_ENT, TT(3), KC_BSPC, KC_ESC,
+ XXXXXXX, KC_MS_BTN3, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX
+ //`--------------' `--------------'
+ ),
+ [_RAISE] = LAYOUT(
+ //|-------------------------------------------------------| |-------------------------------------------------------|
+ KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_BSPC,
+ //|-------------------------------------------------------| |-------------------------------------------------------|
+ KC_LCTL, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_APP, KC_UP,S(KC_INT1), KC_UNDS, KC_DQUO, KC_COLN,
+ //|-------------------------------------------------------| |-------------------------------------------------------|
+ KC_LSFT, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_LEFT, KC_DOWN, KC_RGHT, KC_DOT, KC_SLSH, KC_MINS,
+ //|-------------------------------------------------------| |-------------------------------------------------------|
+ KC_LGUI, DEL_ALT, TT(3), KC_SPC, KC_MS_BTN4, KC_MS_BTN5, KC_ENT, KC_TRNS, KC_BSPC, KC_ESC,
+ XXXXXXX, KC_MS_BTN3, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX
+ //`--------------' `--------------'
+ ),
+ [_TRACKBALL] = LAYOUT(
+ //|-------------------------------------------------------| |-------------------------------------------------------|
+ QK_BOOT, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, RGB_TOG, SCRL_TO, CPI_SW, SCRL_SW, ROT_L15, ROT_R15, XXXXXXX,
+ //|-------------------------------------------------------| |-------------------------------------------------------|
+ XXXXXXX, XXXXXXX, RGB_VAI, RGB_SAI, RGB_HUI, RGB_MOD, SCRL_MO, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
+ //|-------------------------------------------------------| |-------------------------------------------------------|
+ XXXXXXX, XXXXXXX, RGB_VAD, RGB_SAD, RGB_HUD,RGB_RMOD, SCRL_IN, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX,
+ //|-------------------------------------------------------| |-------------------------------------------------------|
+ KC_LGUI, DEL_ALT, KC_TRNS, KC_SPC, KC_MS_BTN1, KC_MS_BTN2, KC_ENT, RS_HENK, KC_BSPC, KC_ESC,
+ XXXXXXX, KC_MS_BTN3, XXXXXXX, XXXXXXX, XXXXXXX, XXXXXXX
+ //`--------------' `--------------'
+ )
+};
+
+// Same function on all layers for now.
+#if defined(ENCODER_MAP_ENABLE)
+const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][NUM_DIRECTIONS] = {
+ [0] = { ENCODER_CCW_CW(KC_PGUP, KC_PGDN) },
+ [1] = { ENCODER_CCW_CW(KC_PGUP, KC_PGDN) },
+ [2] = { ENCODER_CCW_CW(KC_PGUP, KC_PGDN) },
+ [3] = { ENCODER_CCW_CW(KC_PGUP, KC_PGDN) },
+};
+#endif
+
+layer_state_t layer_state_set_user(layer_state_t state) {
+ switch (get_highest_layer(state)) {
+ case _LOWER:
+ #ifdef RGBLIGHT_ENABLE
+ rgblight_sethsv_range(HSV_BLUE, 0, 2);
+ #endif
+ cocot_set_scroll_mode(true);
+ break;
+ case _RAISE:
+ #ifdef RGBLIGHT_ENABLE
+ rgblight_sethsv_range(HSV_RED, 0, 2);
+ #endif
+ cocot_set_scroll_mode(true);
+ break;
+ case _TRACKBALL:
+ #ifdef RGBLIGHT_ENABLE
+ rgblight_sethsv_range(HSV_GREEN, 0, 2);
+ #endif
+ cocot_set_scroll_mode(false);
+ break;
+ default:
+ #ifdef RGBLIGHT_ENABLE
+ rgblight_sethsv_range( 0, 0, 0, 0, 2);
+ #endif
+ cocot_set_scroll_mode(false);
+ break;
+ }
+ #ifdef RGBLIGHT_ENABLE
+ rgblight_set_effect_range( 2, 10);
+ #endif
+ return state;
+};
diff --git a/keyboards/aki27/cocot46plus/matrix.c b/keyboards/aki27/cocot46plus/matrix.c
new file mode 100644
index 000000000000..5f30e382cdf4
--- /dev/null
+++ b/keyboards/aki27/cocot46plus/matrix.c
@@ -0,0 +1,143 @@
+/*
+Copyright 2012-2018 Jun Wako, Jack Humbert, Yiancar
+
+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 .
+*/
+#include "matrix.h"
+#include "wait.h"
+
+static const pin_t row_pins[MATRIX_ROWS] = MATRIX_ROW_PINS;
+static const pin_t col_pins[MATRIX_COLS] = MATRIX_COL_PINS;
+
+static void select_row(uint8_t row) {
+ gpio_set_pin_output(row_pins[row]);
+ gpio_write_pin_low(row_pins[row]);
+}
+
+static void unselect_row(uint8_t row) {
+ gpio_set_pin_input_high(row_pins[row]);
+}
+
+static void unselect_rows(void) {
+ for (uint8_t x = 0; x < MATRIX_ROWS; x++) {
+ gpio_set_pin_input_high(row_pins[x]);
+ }
+}
+
+static void select_col(uint8_t col) {
+ gpio_set_pin_output(col_pins[col]);
+ gpio_write_pin_low(col_pins[col]);
+}
+
+static void unselect_col(uint8_t col) {
+ gpio_set_pin_input_high(col_pins[col]);
+}
+
+static void unselect_cols(void) {
+ for (uint8_t x = 0; x < MATRIX_COLS; x++) {
+ gpio_set_pin_input_high(col_pins[x]);
+ }
+}
+
+static void init_pins(void) {
+ unselect_rows();
+ unselect_cols();
+ for (uint8_t x = 0; x < MATRIX_COLS; x++) {
+ gpio_set_pin_input_high(col_pins[x]);
+ }
+ for (uint8_t x = 0; x < MATRIX_ROWS; x++) {
+ gpio_set_pin_input_high(row_pins[x]);
+ }
+}
+
+static bool read_cols_on_row(matrix_row_t current_matrix[], uint8_t current_row) {
+ // Store last value of row prior to reading
+ matrix_row_t last_row_value = current_matrix[current_row];
+
+ // Clear data in matrix row
+ current_matrix[current_row] = 0;
+
+ // Select row and wait for row selecton to stabilize
+ select_row(current_row);
+ wait_us(30);
+
+ // For each col...
+ for (uint8_t col_index = 0; col_index < MATRIX_COLS; col_index++) {
+ // Select the col pin to read (active low)
+ uint8_t pin_state = gpio_read_pin(col_pins[col_index]);
+
+ // Populate the matrix row with the state of the col pin
+ current_matrix[current_row] |= pin_state ? 0 : (MATRIX_ROW_SHIFTER << col_index);
+ }
+
+ // Unselect row
+ unselect_row(current_row);
+
+ return (last_row_value != current_matrix[current_row]);
+}
+
+static bool read_rows_on_col(matrix_row_t current_matrix[], uint8_t current_col) {
+ bool matrix_changed = false;
+
+ // Select col and wait for col selecton to stabilize
+ select_col(current_col);
+ wait_us(30);
+
+ // For each row...
+ for (uint8_t row_index = 0; row_index < MATRIX_ROWS / 2; row_index++) {
+ uint8_t tmp = row_index + MATRIX_ROWS / 2;
+ // Store last value of row prior to reading
+ matrix_row_t last_row_value = current_matrix[tmp];
+
+ // Check row pin state
+ if (gpio_read_pin(row_pins[row_index]) == 0) {
+ // Pin LO, set col bit
+ current_matrix[tmp] |= (MATRIX_ROW_SHIFTER << current_col);
+ } else {
+ // Pin HI, clear col bit
+ current_matrix[tmp] &= ~(MATRIX_ROW_SHIFTER << current_col);
+ }
+
+ // Determine if the matrix changed state
+ if ((last_row_value != current_matrix[tmp]) && !(matrix_changed)) {
+ matrix_changed = true;
+ }
+ }
+
+ // Unselect col
+ unselect_col(current_col);
+
+ return matrix_changed;
+}
+
+void matrix_init_custom(void) {
+ // initialize key pins
+ init_pins();
+}
+
+bool matrix_scan_custom(matrix_row_t current_matrix[]) {
+ bool changed = false;
+
+ // Set row, read cols
+ for (uint8_t current_row = 0; current_row < MATRIX_ROWS / 2; current_row++) {
+ changed |= read_cols_on_row(current_matrix, current_row);
+ }
+ // else
+ // Set col, read rows
+ for (uint8_t current_col = 0; current_col < MATRIX_COLS; current_col++) {
+ changed |= read_rows_on_col(current_matrix, current_col);
+ }
+
+ return (uint8_t)changed;
+}
diff --git a/keyboards/aki27/cocot46plus/readme.md b/keyboards/aki27/cocot46plus/readme.md
new file mode 100644
index 000000000000..9e5058f46dc2
--- /dev/null
+++ b/keyboards/aki27/cocot46plus/readme.md
@@ -0,0 +1,45 @@
+# cocot46plus
+
+![cocot46plus_photo15](https://i.imgur.com/yCvbMgo.jpeg)
+
+
+cocot46plus is a column-staggered keyboard with 46 keys, a 34mm-trackball and a rotary encoder.
+
+- Keyboard Maintainer: [markstos](https://github.com/markstos)
+- Hardware Supported: cocot46plus PCB, SparkFun Pro Micro - RP2040
+- Hardware Availability: [Yushakobo.jp](https://shop.yushakobo.jp/en/products/6955)
+
+Detailed information is available from the links below:
+
+ - [JP](https://www.notion.so/aki27/cocot46plus-55775bf44a664dae9d6ca342e79e8312)
+ - [EN](https://aki27.notion.site/cocot46plus-Introduction-e6261b0a5ce045f8a0d8535a74844929)
+
+## Build Guides
+
+ - [JP](https://github.com/aki27kbd/cocot46plus/blob/main/doc/buildguide.md)
+ - [EN](https://github.com/aki27kbd/cocot46plus/blob/main/doc/v1/buildguide_en.md)
+
+### Special keycodes
+
+Value | Keycode |Description
+---------|-----------|-----------
+`0x5DA7` | `CPI_SW` |Switch CPI. Low for precision, high for large movements.
+`0x5DA8` | `SCRL_SW` |Switch scroll divider. Larger value equals smaller scroll motion
+`0x5DA9` | `ROT_R15` |Rotate sensor coordinate by 15 degrees clockwise
+`0x5DAA` | `ROT_L15` |Rotate sensor coordinate by 15 degrees counterclockwise
+`0x5DAB` | `SCRL_MO` |Enable scroll mode while being pressed
+`0x5DAC` | `SCRL_TO` |Toggle scroll mode. Once pushed, mouse mode and scroll mode are switched.
+`0x5DAD` | `SCRL_IN` |Invert scroll direction
+
+# VIA Support
+
+ * [aki27 provides VIA JSON files](https://github.com/aki27kbd/cocot46plus/tree/main/firmware)
+
+
+### Gallery
+
+![cocot46plus_photo12](https://i.imgur.com/hPOB98H.jpeg)
+![cocot46plus_photo14](https://i.imgur.com/HrtI9w1.jpeg)
+![cocot46plus_photo05](https://i.imgur.com/LOcxHIV.jpeg)
+![cocot46plus_photo02](https://i.imgur.com/b5O9tKq.jpeg)
+![cocot46plus_photo10](https://i.imgur.com/gDx5e64.jpeg)
diff --git a/keyboards/aki27/cocot46plus/rules.mk b/keyboards/aki27/cocot46plus/rules.mk
new file mode 100644
index 000000000000..b6069b773768
--- /dev/null
+++ b/keyboards/aki27/cocot46plus/rules.mk
@@ -0,0 +1,3 @@
+SRC += matrix.c
+CUSTOM_MATRIX = lite
+POINTING_DEVICE_DRIVER = adns5050