This commit is contained in:
Dylan M. Kozicki 2023-09-15 12:15:53 -04:00 committed by GitHub
commit c40d042778
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 1077 additions and 2 deletions

View file

@ -2,4 +2,5 @@
# SPDX-License-Identifier: MIT
add_subdirectory_ifdef(CONFIG_ZMK_BATTERY battery)
add_subdirectory_ifdef(CONFIG_EC11 ec11)
add_subdirectory_ifdef(CONFIG_EC11 ec11)
add_subdirectory_ifdef(CONFIG_PMW33xx pmw33xx)

View file

@ -2,4 +2,5 @@
# SPDX-License-Identifier: MIT
rsource "battery/Kconfig"
rsource "ec11/Kconfig"
rsource "ec11/Kconfig"
rsource "pmw33xx/Kconfig"

1
app/drivers/sensor/pmw33xx/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
pmw3389_srom.h

View file

@ -0,0 +1,10 @@
# Copyright (c) 2022 The ZMK Contributors
# SPDX-License-Identifier: MIT
zephyr_include_directories(.)
zephyr_include_directories_ifdef(CONFIG_PMW33XX_3389 CONFIG_PMW33XX_3389_SROM_INCLUDE_DIR)
zephyr_library()
zephyr_library_sources(pmw33xx.c)
zephyr_library_sources_ifdef(CONFIG_PMW33XX_TRIGGER pmw33xx_trigger.c)

View file

@ -0,0 +1,69 @@
# Copyright (c) 2022 The ZMK Contributors
# SPDX-License-Identifier: MIT
config PMW33XX
bool "PMW33XX Mouse Sensor"
depends on SPI
help
Enable mouse sensor
The PMW33XX is a 16-bit optical mouse sensor
if PMW33XX
choice
prompt "Sensor"
default PMW33XX_3360
config PMW33XX_3360
bool "Enable PMW3360"
config PMW33XX_3389
bool "Enable PMW3389"
help
PMW3389 requires an external srom included in `pmw3389_srom.h` which we cannot currently include in zmk
endchoice
config PMW33XX_3389_SROM_INCLUDE_DIR
string "PMW3389 SROM Include Dir"
default "."
help
directory where the header with the pmw3389 srom file is located
choice
prompt "Trigger mode"
default PMW33XX_TRIGGER_NONE
help
Specify the type of triggering to be used by the driver.
config PMW33XX_TRIGGER_NONE
bool "No trigger"
config PMW33XX_TRIGGER_GLOBAL_THREAD
bool "Use global thread"
depends on GPIO
select PMW33XX_TRIGGER
config PMW33XX_TRIGGER_OWN_THREAD
bool "Use own thread"
depends on GPIO
select PMW33XX_TRIGGER
endchoice
config PMW33XX_TRIGGER
bool
config PMW33XX_THREAD_PRIORITY
int "Thread priority"
depends on PMW33XX_TRIGGER_OWN_THREAD
default 10
help
Priority of thread used by the driver to handle interrupts.
config PMW33XX_THREAD_STACK_SIZE
int "Thread stack size"
depends on PMW33XX_TRIGGER_OWN_THREAD
default 1024
help
Stack size of thread used by the driver to handle interrupts.
endif # PMW33XX

View file

@ -0,0 +1,291 @@
/*
This SROM is provided "AS IS" by PixArt Imaging Inc., WITHOUT WARRANTY
OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL PIXART
IMAGING INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THIS
SROM OR THE USE OR OTHER DEALINGS IN THIS SROM.
*/
#ifndef ZEPHYR_DRIVERS_SENSOR_PIXART_PMW33XX_PMW3360_SROM_H_
#define ZEPHYR_DRIVERS_SENSOR_PIXART_PMW33XX_PMW3360_SROM_H_
#include <stdint.h>
static const uint8_t SROM[] = {
0x01, 0x05, 0x8d, 0x92, 0x66, 0x67, 0x1e, 0xbe, 0xfe, 0x5f, 0x1d, 0xb8, 0xf2, 0x66, 0x4e,
0xff, 0x5d, 0x38, 0xf2, 0x46, 0x0c, 0x98, 0x97, 0x8d, 0x79, 0x51, 0x20, 0xc2, 0x06, 0x8e,
0x9e, 0xbe, 0xfe, 0x7e, 0x5f, 0x1d, 0xb8, 0xd3, 0x24, 0xca, 0x16, 0x8f, 0x7d, 0x78, 0x53,
0x05, 0x88, 0x73, 0x45, 0xe9, 0x55, 0x22, 0xa7, 0xae, 0xd8, 0x32, 0xe6, 0x2f, 0xbd, 0xf8,
0x72, 0x47, 0x0c, 0x7b, 0x74, 0x6a, 0x56, 0x2e, 0xbf, 0xdd, 0x38, 0xd5, 0x20, 0xca, 0x16,
0xae, 0xde, 0x1f, 0x9d, 0xb8, 0xf2, 0x47, 0x0c, 0x7b, 0x55, 0x28, 0xd2, 0x26, 0xaf, 0xdc,
0x3a, 0xd7, 0x2c, 0xbb, 0xd5, 0x09, 0x90, 0xa2, 0xa7, 0xcc, 0xfb, 0x74, 0x4b, 0xf5, 0x49,
0x10, 0x83, 0x84, 0x8a, 0x77, 0x4d, 0x18, 0xb2, 0xe6, 0x4e, 0x1e, 0x9f, 0xbc, 0xfa, 0x6a,
0xea, 0xab, 0x55, 0x91, 0xa9, 0xda, 0x58, 0xa9, 0xe1, 0x1a, 0xc2, 0x52, 0x1c, 0x0d, 0xef,
0x50, 0x71, 0x04, 0x21, 0x93, 0x87, 0x0e, 0xb1, 0xa9, 0x4a, 0xc0, 0x24, 0xaf, 0xe3, 0x26,
0xa2, 0x8d, 0xa1, 0x6d, 0xf2, 0x88, 0x9e, 0x99, 0xbb, 0xf2, 0x62, 0x38, 0xfe, 0x78, 0x1d,
0x58, 0x19, 0x9b, 0xbe, 0x10, 0x6c, 0x15, 0x9e, 0x50, 0x8b, 0x99, 0x40, 0x92, 0x01, 0x38,
0xb6, 0x97, 0x83, 0x51, 0x59, 0xa6, 0xb7, 0xc9, 0x48, 0xfd, 0x68, 0x21, 0x78, 0xf4, 0x2e,
0x86, 0x61, 0xb0, 0xb2, 0x2b, 0x5b, 0xf0, 0x1b, 0x71, 0xa3, 0x0a, 0xd5, 0xd6, 0x30, 0x7a,
0x0c, 0xf8, 0xaf, 0xc6, 0x54, 0x6b, 0x89, 0x30, 0x58, 0xe8, 0xe2, 0x0d, 0x39, 0x2f, 0x47,
0xa0, 0x41, 0x74, 0x5d, 0xd6, 0xf3, 0x85, 0xb7, 0x66, 0x59, 0x51, 0x74, 0x3d, 0xfe, 0xee,
0x3a, 0x1e, 0x2a, 0x5f, 0x93, 0x0c, 0x3f, 0xd4, 0x4d, 0x24, 0x13, 0x2c, 0xf2, 0x7b, 0x4d,
0x06, 0x60, 0x2e, 0x39, 0xa9, 0xd4, 0x72, 0x36, 0xb6, 0x4d, 0xea, 0x8c, 0xd9, 0xa7, 0xbc,
0x38, 0xe7, 0xbb, 0xb7, 0x7b, 0x04, 0x08, 0x83, 0x5a, 0x27, 0x6f, 0x42, 0xc6, 0x7e, 0xbd,
0x97, 0x0e, 0x55, 0xdc, 0x79, 0x63, 0xd8, 0x89, 0xc1, 0x83, 0x3d, 0x34, 0x01, 0x76, 0xff,
0xde, 0x7f, 0x65, 0x4b, 0xb3, 0x46, 0x56, 0x8d, 0x9e, 0x6f, 0x1f, 0x2b, 0xa4, 0x69, 0x54,
0xde, 0x1c, 0x2d, 0xa8, 0x51, 0x7e, 0xdf, 0xbb, 0x18, 0x90, 0x27, 0xaf, 0x79, 0xd1, 0x86,
0x4f, 0x44, 0x88, 0x7f, 0xb9, 0x80, 0x21, 0xa9, 0x5d, 0x7b, 0xd4, 0x81, 0x21, 0xa9, 0x13,
0x59, 0x72, 0x58, 0x11, 0xe3, 0xf2, 0xf7, 0xae, 0xc3, 0xc2, 0x64, 0x1d, 0xfb, 0xd8, 0x91,
0x2d, 0x13, 0xb5, 0x0e, 0x67, 0xdb, 0xbc, 0x63, 0xde, 0xa0, 0x86, 0x49, 0x6c, 0x40, 0x82,
0x82, 0x3f, 0xeb, 0x38, 0x22, 0xa8, 0x20, 0x1e, 0xc5, 0x5f, 0x25, 0xea, 0xaf, 0xe6, 0x78,
0x1c, 0x41, 0x0b, 0x5a, 0x94, 0xcc, 0x8d, 0x0d, 0xc5, 0xb8, 0x9c, 0x1a, 0x9f, 0x6d, 0xa8,
0x57, 0xe9, 0x1a, 0xf0, 0xad, 0x6c, 0x26, 0x5f, 0xb8, 0x38, 0x16, 0x0e, 0x28, 0xd6, 0x76,
0x5a, 0xc2, 0xb7, 0x6a, 0x9e, 0x26, 0x9d, 0x3e, 0x1f, 0x25, 0xb0, 0x14, 0x46, 0xcd, 0x67,
0x49, 0x93, 0x13, 0x81, 0x01, 0x46, 0x72, 0x31, 0x42, 0x91, 0x87, 0x6c, 0x1c, 0xb8, 0x08,
0x72, 0x6a, 0x33, 0x64, 0xed, 0xc0, 0x99, 0xb9, 0xf6, 0x34, 0xe9, 0xa5, 0x6c, 0x57, 0x9a,
0x72, 0x18, 0x48, 0x62, 0xc1, 0x88, 0xcf, 0xa3, 0x50, 0x53, 0x50, 0xdf, 0xc8, 0x9f, 0xf0,
0xb6, 0xa2, 0x23, 0xc4, 0xaa, 0xe3, 0xd0, 0xe2, 0xab, 0x76, 0xc8, 0x4a, 0x02, 0x21, 0xdd,
0xf3, 0x59, 0xdc, 0x30, 0x6e, 0xb5, 0x42, 0xe2, 0x9d, 0x8a, 0xdf, 0xfd, 0xa5, 0x41, 0x75,
0x01, 0x83, 0xbe, 0x47, 0xa5, 0x21, 0x30, 0x3b, 0x0e, 0x33, 0x2e, 0x74, 0xaf, 0x27, 0x90,
0xf4, 0x20, 0xa7, 0x1b, 0xff, 0x77, 0x01, 0xab, 0x79, 0x0a, 0xfb, 0x86, 0x1e, 0x1f, 0x22,
0x6d, 0x75, 0x75, 0xfc, 0xe0, 0x8c, 0xa2, 0x72, 0x0f, 0x45, 0x48, 0xf9, 0x43, 0x10, 0xf0,
0x57, 0x15, 0x17, 0x74, 0x40, 0x8f, 0x77, 0x69, 0x8a, 0xd4, 0x0f, 0x25, 0x27, 0x0a, 0xe8,
0x84, 0x73, 0x41, 0xb9, 0x5f, 0xb6, 0xc8, 0x2f, 0x02, 0x83, 0xdc, 0x1e, 0x1c, 0xdb, 0x3f,
0x2d, 0x58, 0xf7, 0x5e, 0xfd, 0x6f, 0xda, 0xad, 0xdc, 0x43, 0x01, 0x22, 0xc6, 0x45, 0x9c,
0xec, 0x56, 0x8a, 0x1a, 0x4e, 0xaa, 0xae, 0x3a, 0xa1, 0xf3, 0xf1, 0x9a, 0x97, 0x8d, 0x79,
0x51, 0x01, 0xf5, 0x31, 0x04, 0xcd, 0x2a, 0xbc, 0xfd, 0xac, 0x59, 0x1b, 0x0a, 0xe2, 0x26,
0xdd, 0x2f, 0x96, 0xaa, 0x62, 0xc5, 0x6d, 0xb8, 0xe1, 0x72, 0x4e, 0x4e, 0xb7, 0x4f, 0x9f,
0xaa, 0x33, 0x75, 0x8b, 0x43, 0x44, 0x0a, 0xc3, 0x0a, 0x5e, 0x9c, 0xdb, 0x1e, 0x4e, 0xbd,
0x0f, 0xec, 0x09, 0x96, 0x5a, 0x37, 0x6d, 0x10, 0x44, 0xd4, 0x91, 0xc0, 0xc3, 0x0d, 0x35,
0x62, 0xcf, 0x0a, 0xb1, 0x1a, 0x8a, 0xda, 0xa8, 0xcf, 0xbc, 0x3a, 0xb2, 0x4f, 0x59, 0x29,
0xd9, 0x91, 0x96, 0x0d, 0x6b, 0x9c, 0xcf, 0x34, 0x5b, 0x76, 0x7b, 0xb2, 0xb2, 0xce, 0xbf,
0x72, 0xd9, 0x96, 0x4a, 0xc0, 0x2d, 0x89, 0x33, 0xd0, 0xe4, 0xbe, 0x69, 0x7f, 0x1c, 0x9e,
0x71, 0x19, 0x12, 0xf6, 0x74, 0xfb, 0xd6, 0x41, 0x95, 0x69, 0xf0, 0xe9, 0xa7, 0x50, 0x82,
0x04, 0x78, 0x4d, 0x99, 0xb3, 0xa7, 0xfe, 0xee, 0x7f, 0xed, 0x56, 0x57, 0x57, 0xe9, 0xd3,
0x6a, 0x43, 0xf4, 0x0b, 0x6d, 0xba, 0x34, 0xde, 0xf8, 0x4c, 0x45, 0xae, 0x00, 0x32, 0x1a,
0x4e, 0xff, 0x54, 0x60, 0x6a, 0xd9, 0x59, 0x18, 0xd3, 0xbe, 0x5a, 0x94, 0x16, 0x9d, 0xec,
0xdf, 0xb4, 0x48, 0x8e, 0x6f, 0x19, 0xf8, 0xe6, 0xec, 0x7f, 0xb7, 0x49, 0x92, 0xb3, 0xb6,
0xec, 0x7e, 0xdc, 0x08, 0x3b, 0xe5, 0x5b, 0x88, 0xf9, 0x92, 0xf3, 0x7c, 0x9d, 0x7c, 0x22,
0xf2, 0x5d, 0x7d, 0x76, 0x07, 0x2e, 0x42, 0xd6, 0x9e, 0x5a, 0xbc, 0x7d, 0xfd, 0xb5, 0x92,
0x4a, 0x7f, 0xbf, 0xac, 0xc0, 0xb6, 0x18, 0x8b, 0x02, 0x71, 0xae, 0xc7, 0xa8, 0x8c, 0x19,
0xc1, 0x0a, 0x36, 0x3e, 0xa4, 0x2d, 0xa6, 0xbb, 0xe8, 0x77, 0x34, 0x45, 0xca, 0x60, 0x52,
0xf0, 0x26, 0xf7, 0x58, 0x68, 0x34, 0x28, 0xb5, 0x29, 0xe5, 0xb8, 0x65, 0x0f, 0xc8, 0xc2,
0x64, 0x50, 0x91, 0x12, 0xa1, 0x7b, 0xd7, 0x09, 0x74, 0x5f, 0xcc, 0xac, 0x9d, 0xac, 0x0a,
0xd1, 0x46, 0xbe, 0xc2, 0x2d, 0xa6, 0x67, 0x69, 0x69, 0x55, 0x8a, 0xbd, 0x67, 0xd9, 0x31,
0xc7, 0x80, 0x7c, 0xd5, 0xb2, 0xbe, 0x83, 0x17, 0x7a, 0x2e, 0xf4, 0x3e, 0x14, 0xa5, 0x62,
0x77, 0xa5, 0xdb, 0x77, 0x58, 0x35, 0x5f, 0xc4, 0x6c, 0xd2, 0xf2, 0x38, 0x91, 0x74, 0x80,
0x95, 0x52, 0xd2, 0xaf, 0xe2, 0x1b, 0x12, 0xfe, 0x4b, 0x5f, 0x84, 0x5f, 0x7d, 0x7e, 0x0b,
0xd9, 0x42, 0x72, 0xf1, 0x32, 0x1d, 0x8d, 0x5c, 0xcb, 0x20, 0x05, 0x4f, 0xbe, 0xbf, 0x40,
0xe9, 0xa6, 0x9f, 0xff, 0x05, 0xe1, 0x73, 0x52, 0x65, 0xb4, 0x59, 0x45, 0x04, 0x10, 0xe1,
0xdc, 0x0b, 0x30, 0xaa, 0x23, 0x4d, 0xb9, 0x58, 0xe5, 0xf1, 0xa3, 0x9c, 0xf2, 0xf7, 0xaf,
0xbc, 0xe3, 0xa7, 0x0d, 0x68, 0x97, 0x6c, 0x2b, 0x33, 0x60, 0xe3, 0xce, 0x7c, 0xda, 0xd1,
0x2d, 0x78, 0x52, 0x10, 0xa0, 0xf7, 0x9a, 0xf4, 0x79, 0xdb, 0xa5, 0x2a, 0x71, 0xc6, 0xcf,
0xa0, 0x68, 0xd0, 0x32, 0x2a, 0xd3, 0xb2, 0xe8, 0x03, 0x27, 0xbe, 0x55, 0xfd, 0x0e, 0x90,
0xa2, 0x76, 0x8c, 0xdc, 0xbd, 0x69, 0x9c, 0xb6, 0x18, 0x92, 0xe3, 0xb3, 0x23, 0x1d, 0x3c,
0x85, 0x2a, 0x2b, 0x04, 0x3a, 0xf5, 0xee, 0xf8, 0xd2, 0xdd, 0x6d, 0x52, 0xa2, 0x45, 0x75,
0xd9, 0xa1, 0x03, 0x23, 0x83, 0x24, 0x04, 0xe7, 0xee, 0xa2, 0x14, 0x4e, 0xa9, 0xde, 0x4e,
0x9d, 0x24, 0x1a, 0x63, 0xd3, 0x4b, 0xf7, 0x71, 0xc1, 0xe7, 0xfb, 0x48, 0xa4, 0x7c, 0x39,
0xcb, 0x80, 0xdd, 0x5e, 0xaf, 0x0d, 0xca, 0xef, 0x58, 0x17, 0xf4, 0xca, 0x0c, 0x00, 0x30,
0x68, 0x3e, 0x5d, 0x9b, 0xc3, 0x19, 0x27, 0x7a, 0x35, 0x32, 0x5c, 0x7b, 0x92, 0x16, 0x7f,
0x6e, 0x86, 0x6b, 0x50, 0x7a, 0xd6, 0x15, 0x10, 0x16, 0xa8, 0x28, 0xb1, 0xa1, 0xd8, 0xda,
0xc8, 0xfd, 0x5b, 0xe2, 0xc0, 0xd6, 0x8d, 0x75, 0xbd, 0x1c, 0x0b, 0x27, 0xfe, 0x1d, 0x09,
0x23, 0x13, 0x4f, 0x5a, 0x5a, 0xf8, 0xbe, 0x5d, 0x31, 0x8a, 0x81, 0xaf, 0xbe, 0xed, 0x00,
0x43, 0x14, 0x8f, 0xa5, 0x4a, 0xfe, 0x90, 0xe1, 0x67, 0x25, 0x29, 0x52, 0x2f, 0x26, 0x17,
0xef, 0x6e, 0xe6, 0x1e, 0xaf, 0x7f, 0x4a, 0x40, 0x15, 0xc7, 0x6e, 0x8d, 0x60, 0x92, 0xd6,
0x8d, 0x95, 0xca, 0xff, 0x8e, 0xfe, 0x4b, 0x8d, 0x1a, 0x83, 0x40, 0xe6, 0xb7, 0xbc, 0x6b,
0xd6, 0x39, 0x53, 0xd0, 0x4a, 0xe6, 0x1f, 0x1f, 0xb1, 0x16, 0x6a, 0xae, 0x6a, 0x6d, 0xe3,
0xe6, 0xed, 0x4e, 0xff, 0x49, 0x28, 0xc7, 0xaf, 0xb4, 0x14, 0x9f, 0x85, 0x9f, 0xfe, 0x6a,
0x92, 0x93, 0x9c, 0x6f, 0xff, 0x4a, 0xd4, 0x3e, 0x26, 0xd9, 0x72, 0x4f, 0x01, 0xe2, 0x54,
0x06, 0xc6, 0x7d, 0xb8, 0xef, 0x0b, 0x04, 0x56, 0x3a, 0x51, 0x41, 0xe2, 0x1d, 0xc2, 0x96,
0x95, 0xd1, 0x66, 0x16, 0x3b, 0x50, 0x36, 0x3f, 0x2e, 0xf2, 0xb2, 0x25, 0x2d, 0x59, 0x0f,
0x23, 0xf2, 0x9d, 0xb0, 0xee, 0x59, 0x89, 0xd0, 0x79, 0x30, 0xc7, 0x54, 0x9b, 0xec, 0xf8,
0xd7, 0xdc, 0x5a, 0x11, 0x1d, 0xfb, 0xf0, 0x82, 0x33, 0x3c, 0xff, 0x17, 0xff, 0xfc, 0x92,
0xc6, 0x6f, 0x3d, 0x5d, 0x99, 0x85, 0x2a, 0xa1, 0x04, 0xe8, 0x21, 0xed, 0x12, 0x2b, 0x7d,
0xbc, 0xa3, 0x36, 0x9b, 0x9f, 0xfd, 0x5d, 0x60, 0x66, 0xe9, 0x39, 0x5e, 0x34, 0x29, 0xa7,
0x08, 0x56, 0xf7, 0x4d, 0x19, 0x8d, 0x91, 0xff, 0xc8, 0x8a, 0xe7, 0xe8, 0x22, 0x00, 0x35,
0x68, 0x34, 0x93, 0xe7, 0x3b, 0x41, 0xbb, 0xf6, 0x58, 0x2f, 0x10, 0x66, 0x77, 0x69, 0xcd,
0x94, 0xb9, 0xbe, 0x59, 0x73, 0x4f, 0xc3, 0x11, 0xa1, 0xb3, 0x13, 0xe2, 0x82, 0xf1, 0x05,
0xcb, 0xa7, 0x75, 0xf6, 0x01, 0xb2, 0x24, 0xa9, 0x59, 0x05, 0x59, 0x46, 0xc9, 0x25, 0x39,
0x36, 0xee, 0x48, 0x90, 0x83, 0x89, 0xc4, 0xdb, 0xa3, 0x83, 0xd0, 0xd3, 0x62, 0x3f, 0x5e,
0x0e, 0x0c, 0xb7, 0x77, 0xb3, 0xd6, 0xbb, 0x37, 0x70, 0xb2, 0xb3, 0x87, 0x60, 0xd7, 0x8a,
0xe2, 0x99, 0xa9, 0x0f, 0x18, 0x16, 0xf6, 0xcd, 0x14, 0x4e, 0x2c, 0x7e, 0xfe, 0xf9, 0xa4,
0x48, 0xfb, 0xb9, 0x60, 0x13, 0x01, 0xd2, 0x6e, 0xdc, 0x3f, 0xe7, 0x2d, 0x7f, 0xe1, 0x11,
0x96, 0x12, 0x9a, 0x90, 0x48, 0x2b, 0x76, 0x78, 0xa6, 0xdd, 0x67, 0x48, 0x68, 0x42, 0xfd,
0x74, 0xb6, 0x51, 0xd7, 0x99, 0x07, 0x7d, 0x8b, 0x02, 0xd6, 0x68, 0x36, 0x97, 0x6d, 0x49,
0x28, 0xbf, 0xcc, 0x23, 0x8f, 0xed, 0x78, 0x4c, 0x49, 0xb0, 0xd1, 0x9a, 0x3d, 0x1c, 0xdd,
0xf0, 0xeb, 0xd5, 0xd4, 0xc2, 0x12, 0xae, 0x5d, 0x00, 0xe0, 0xf4, 0x84, 0x10, 0x08, 0x76,
0x28, 0x5a, 0x5e, 0xde, 0xe3, 0xad, 0x4e, 0x56, 0xcc, 0x22, 0x85, 0x5f, 0xa9, 0xca, 0xa5,
0x4e, 0xc6, 0x82, 0xf0, 0xbb, 0x5a, 0x82, 0xbf, 0x32, 0x54, 0xd2, 0x8a, 0x12, 0x05, 0x6f,
0xd8, 0xd1, 0xc0, 0x60, 0x00, 0x41, 0x03, 0xf4, 0xa8, 0xd6, 0xee, 0x9e, 0x5a, 0x75, 0xea,
0x76, 0x88, 0xf1, 0x2d, 0x8d, 0x63, 0xfc, 0x14, 0xe9, 0x7b, 0xeb, 0x0b, 0x49, 0xa4, 0x8b,
0x86, 0xf4, 0x97, 0x61, 0x22, 0x29, 0x32, 0x23, 0x80, 0x2e, 0x59, 0x44, 0xea, 0xf5, 0x56,
0x18, 0x51, 0xc0, 0x60, 0xe1, 0x83, 0x66, 0x1f, 0x1f, 0xa1, 0x13, 0x64, 0xae, 0xbc, 0x59,
0xd0, 0xc4, 0x38, 0x70, 0x3f, 0xb5, 0xb5, 0xa2, 0xdc, 0x89, 0x77, 0x70, 0x5a, 0x86, 0xb7,
0xde, 0x67, 0x3c, 0x22, 0x83, 0xc8, 0x62, 0x77, 0xb6, 0x5d, 0x7e, 0x41, 0x99, 0x70, 0x7d,
0xc3, 0x27, 0x90, 0x7f, 0x3c, 0xc6, 0x90, 0xc7, 0xb9, 0x32, 0xd8, 0x01, 0xdf, 0x02, 0x20,
0x27, 0x8f, 0x7b, 0x76, 0xb3, 0x0d, 0xfa, 0x93, 0x46, 0x6f, 0xde, 0x23, 0x12, 0xb9, 0x4e,
0xb8, 0x36, 0x8e, 0x9c, 0x3a, 0x2f, 0xd4, 0x2b, 0x54, 0xab, 0x63, 0xe6, 0xf1, 0x62, 0x8c,
0xd1, 0x1e, 0x87, 0x48, 0x2d, 0x83, 0x93, 0xfe, 0xac, 0x29, 0x82, 0xc2, 0x3c, 0x4f, 0xd0,
0x19, 0xe7, 0xa3, 0x99, 0x8d, 0x7d, 0x64, 0x15, 0xde, 0x64, 0xdb, 0xc1, 0x73, 0xe0, 0x78,
0x24, 0x23, 0x9e, 0x8a, 0xfb, 0xe2, 0xea, 0xd5, 0x0f, 0x93, 0x51, 0x62, 0x38, 0x41, 0x3e,
0x40, 0xa4, 0x2f, 0x7e, 0xb8, 0x11, 0x5c, 0xd3, 0x46, 0x0a, 0x74, 0xcb, 0xb7, 0xd0, 0x15,
0x96, 0xf1, 0xe7, 0x48, 0x32, 0x05, 0x69, 0xa8, 0xda, 0x56, 0xee, 0x9f, 0x6a, 0x95, 0xe6,
0x0d, 0xd2, 0x2c, 0xc1, 0xc2, 0xa5, 0xf4, 0xd8, 0xc6, 0xd7, 0xf6, 0x1f, 0x6f, 0x88, 0x78,
0xab, 0xd4, 0x1f, 0x53, 0xa0, 0xa1, 0x3b, 0x03, 0xb1, 0x4a, 0xcd, 0xbe, 0x25, 0x1c, 0x6f,
0xb4, 0x30, 0x41, 0xb5, 0x4a, 0xaa, 0xa5, 0x38, 0x91, 0x77, 0xce, 0x48, 0xc8, 0xe1, 0x34,
0xc2, 0x85, 0xdc, 0x9b, 0x24, 0x6f, 0x63, 0x12, 0xaa, 0x97, 0xaf, 0x9e, 0x37, 0x1e, 0xaf,
0x94, 0x2c, 0x5c, 0x43, 0xa6, 0x93, 0x17, 0x7d, 0x1c, 0x77, 0x18, 0x0f, 0xb5, 0xf2, 0x66,
0x4a, 0xaf, 0xd9, 0x92, 0xfb, 0x47, 0xfc, 0x1f, 0x7a, 0xdb, 0x77, 0x0b, 0x11, 0x61, 0xe0,
0x85, 0x12, 0x96, 0xf7, 0x55, 0x09, 0x90, 0xa2, 0x77, 0xdb, 0x9c, 0x9c, 0x8b, 0x04, 0x55,
0x45, 0x39, 0x64, 0x4e, 0x46, 0x5f, 0xa2, 0x98, 0xbc, 0xd6, 0x1b, 0x5d, 0x5f, 0x67, 0x21,
0xc7, 0x12, 0xe5, 0xe6, 0x13, 0x93, 0x7b, 0x83, 0xd8, 0x5b, 0xcc, 0x2e, 0x77, 0xce, 0x56,
0x97, 0xdc, 0x96, 0x70, 0xcc, 0x47, 0x1a, 0x79, 0x1f, 0xb0, 0x6a, 0xe4, 0x7c, 0xd6, 0xa7,
0x28, 0x72, 0x7a, 0x1e, 0xac, 0x54, 0xc0, 0x5d, 0x8c, 0xa1, 0x00, 0xf4, 0x2e, 0x86, 0x28,
0x3a, 0x82, 0xce, 0xbc, 0xf0, 0xfd, 0x2d, 0xb1, 0xc4, 0x9f, 0x6d, 0x6b, 0xba, 0x9e, 0x9b,
0xec, 0xb5, 0x38, 0xe2, 0xe9, 0xf8, 0x57, 0x74, 0xa6, 0x9b, 0x7b, 0xec, 0xe2, 0x90, 0x0d,
0xec, 0x3e, 0xf0, 0x1b, 0x2b, 0x38, 0x9c, 0x82, 0xd9, 0xd1, 0xbe, 0xe1, 0x08, 0x7f, 0x02,
0x54, 0xbc, 0x0b, 0x90, 0x14, 0x57, 0xa2, 0x4e, 0x56, 0xbe, 0x1b, 0xdf, 0x48, 0x9c, 0x17,
0xa1, 0x70, 0xa2, 0x8c, 0x74, 0x74, 0x24, 0xbf, 0xe0, 0x46, 0xb7, 0xdc, 0xa4, 0xb5, 0x66,
0x44, 0xb3, 0x53, 0x0e, 0xa4, 0xe5, 0xb4, 0x83, 0x06, 0x1f, 0x78, 0x2a, 0xe2, 0x16, 0x5c,
0x79, 0x00, 0xab, 0x0a, 0x08, 0x57, 0xe5, 0xbc, 0x2c, 0x9b, 0x91, 0x19, 0xf6, 0x1d, 0x31,
0x25, 0xbb, 0x9b, 0xb5, 0x89, 0x32, 0xb7, 0x53, 0xb9, 0x49, 0xa4, 0x55, 0xc5, 0x9d, 0x2b,
0xa1, 0xeb, 0xd5, 0xec, 0x02, 0x40, 0x14, 0x44, 0x35, 0xc1, 0x65, 0xd7, 0xae, 0x4c, 0xf8,
0x16, 0xf5, 0x70, 0x62, 0x28, 0xcd, 0x58, 0x71, 0x01, 0xcb, 0x85, 0x09, 0x24, 0x91, 0xf0,
0x18, 0xfa, 0xc6, 0x37, 0x07, 0xde, 0xe7, 0x43, 0xed, 0x3a, 0xeb, 0x98, 0x97, 0xf4, 0xc5,
0xf3, 0x60, 0xa5, 0x83, 0x60, 0x1a, 0xf1, 0x81, 0x03, 0x06, 0x2c, 0x1f, 0x38, 0x71, 0x61,
0x30, 0x21, 0x8a, 0x49, 0xb4, 0x2a, 0xa6, 0x03, 0x0e, 0x1d, 0x1d, 0x79, 0xc0, 0xe5, 0x5d,
0xd1, 0x82, 0x37, 0x1b, 0x70, 0x3a, 0xd2, 0x65, 0x48, 0x59, 0xc0, 0xa2, 0xf3, 0x8b, 0x82,
0x24, 0xf5, 0xfe, 0x2a, 0xdd, 0x8d, 0x3a, 0xe9, 0xe5, 0x1c, 0x92, 0xc7, 0x6a, 0x43, 0xde,
0x78, 0xb3, 0x33, 0xa0, 0x9a, 0x78, 0x4a, 0x54, 0xba, 0x01, 0x84, 0xd2, 0xb2, 0xa4, 0x6f,
0x28, 0x21, 0xf2, 0xc4, 0x21, 0x9f, 0x18, 0x72, 0x16, 0x46, 0x6d, 0xfa, 0xf2, 0xa7, 0x7c,
0x99, 0xa4, 0x2c, 0x93, 0x4d, 0xba, 0xdd, 0xa7, 0x59, 0x50, 0x0b, 0x34, 0x48, 0x63, 0x6f,
0x0d, 0x4b, 0x81, 0x22, 0x3b, 0x24, 0x9b, 0x37, 0x4b, 0xd3, 0x94, 0x23, 0xc0, 0x71, 0x39,
0x91, 0xd0, 0x06, 0x2e, 0xd2, 0xae, 0x7c, 0xfd, 0xfd, 0x4d, 0x4a, 0x95, 0x0a, 0xd0, 0x84,
0xbf, 0x8c, 0x5c, 0xe4, 0xc1, 0x10, 0xfa, 0xe6, 0x26, 0x18, 0xea, 0x75, 0x3e, 0x7d, 0x0b,
0xc5, 0x9d, 0xbb, 0x14, 0x3c, 0xa5, 0xe3, 0x19, 0x2b, 0xdd, 0xcd, 0xbb, 0xb4, 0x48, 0x9e,
0x8c, 0xa5, 0xf2, 0xcb, 0x19, 0xa9, 0x8f, 0x0c, 0x0b, 0x36, 0x73, 0xd7, 0x78, 0x2b, 0x64,
0xc9, 0x8c, 0x4a, 0xb2, 0x8f, 0xe9, 0xd9, 0x51, 0xb1, 0x84, 0x49, 0xd1, 0xec, 0x73, 0xa6,
0xb1, 0x41, 0x70, 0xa0, 0xd3, 0xea, 0xb4, 0xf8, 0x50, 0x57, 0xb6, 0x69, 0xda, 0x4a, 0xe6,
0xe0, 0x73, 0xba, 0xdc, 0x98, 0xc4, 0x0e, 0xab, 0xc7, 0xbd, 0x8a, 0xf6, 0xe3, 0xc1, 0x0b,
0xc3, 0x5b, 0x48, 0xa1, 0x79, 0xab, 0xae, 0x9b, 0x17, 0xbd, 0x56, 0x3b, 0x0c, 0x38, 0xbd,
0xed, 0x86, 0x95, 0x05, 0xf4, 0x32, 0xf9, 0xdc, 0x87, 0x4f, 0x78, 0x9a, 0xb0, 0x6f, 0x2b,
0x76, 0xd2, 0xf4, 0x1f, 0x65, 0xf8, 0xd0, 0x9f, 0x8d, 0x3c, 0xb2, 0x53, 0x8c, 0xca, 0xa0,
0x2b, 0x6d, 0xfb, 0x65, 0x96, 0xde, 0x7c, 0x64, 0xbb, 0xf7, 0x7e, 0x3d, 0x8d, 0xfb, 0xd1,
0x2d, 0xf1, 0xc3, 0x1a, 0x66, 0x8a, 0x8f, 0x5e, 0x89, 0x37, 0x19, 0xe7, 0x9b, 0xee, 0xf0,
0xc1, 0xe7, 0xac, 0xe5, 0x15, 0x2f, 0x6d, 0xfb, 0x57, 0xca, 0x78, 0xd0, 0xaa, 0x19, 0xc0,
0x80, 0x67, 0xc9, 0x2f, 0x81, 0x26, 0x7f, 0xbe, 0xdf, 0xde, 0x50, 0x00, 0x2b, 0x1b, 0x17,
0x2a, 0x5d, 0x54, 0xfa, 0x46, 0xc1, 0x3f, 0xb7, 0x2f, 0xc8, 0x31, 0xf4, 0x58, 0x43, 0x36,
0xae, 0x91, 0xc4, 0x46, 0xc4, 0x93, 0xaf, 0x05, 0x9e, 0xa3, 0xba, 0x0c, 0x07, 0x2f, 0x0c,
0xeb, 0x2f, 0x4d, 0x4a, 0x90, 0xd8, 0xc0, 0x51, 0x0f, 0xa5, 0x97, 0x09, 0x16, 0xfa, 0x24,
0xc3, 0x99, 0xe6, 0x1c, 0x9e, 0xed, 0x03, 0x76, 0x57, 0xce, 0x29, 0x73, 0x54, 0x19, 0x5a,
0x20, 0x65, 0x52, 0xa6, 0xfa, 0x97, 0x00, 0x52, 0x23, 0xbb, 0x74, 0x9b, 0x6e, 0xf3, 0x25,
0x94, 0x9c, 0x66, 0x0f, 0x8b, 0x67, 0x62, 0x1a, 0x13, 0xdb, 0xd5, 0xdb, 0xdb, 0xb9, 0x11,
0x02, 0x13, 0x63, 0xe4, 0x6e, 0x41, 0x8a, 0xa0, 0xc2, 0x52, 0x71, 0x66, 0xde, 0x3b, 0x3d,
0x6c, 0xd3, 0xaa, 0x5f, 0x78, 0x3b, 0xf2, 0x7b, 0xad, 0x71, 0x48, 0x2e, 0x06, 0x90, 0x4c,
0x76, 0x89, 0x99, 0xb5, 0x91, 0x61, 0x29, 0x74, 0x8d, 0x90, 0xd6, 0x1b, 0x60, 0x11, 0xf6,
0xc0, 0xa0, 0xc7, 0x3c, 0x1e, 0xf6, 0xec, 0x80, 0x91, 0xe8, 0x6d, 0x46, 0xe0, 0x2c, 0xda,
0x25, 0xdb, 0x18, 0xdb, 0xb1, 0xbe, 0x7c, 0x87, 0x14, 0xa9, 0xa3, 0x46, 0xdb, 0x6e, 0xeb,
0x5d, 0x98, 0xd2, 0x4c, 0xfa, 0x09, 0x13, 0x71, 0xee, 0x51, 0xae, 0x5d, 0x57, 0x79, 0x80,
0x02, 0x43, 0x7b, 0xf7, 0x92, 0x3c, 0xf9, 0x03, 0x07, 0x4f, 0x6a, 0x53, 0x9e, 0x35, 0x2d,
0x40, 0x29, 0x7d, 0x44, 0x39, 0xd2, 0xb4, 0x48, 0xa7, 0x4f, 0xa5, 0x90, 0x9d, 0xb7, 0x4e,
0xa0, 0xb5, 0xb7, 0x92, 0x0f, 0x1c, 0x18, 0xdd, 0x4c, 0xff, 0xd4, 0xf9, 0x53, 0xd1, 0x82,
0x38, 0xc5, 0xcc, 0xe2, 0x36, 0x2d, 0xf7, 0x18, 0x07, 0xda, 0x5b, 0xf6, 0xef, 0xe5, 0xcb,
0xaa, 0x90, 0xd2, 0x84, 0x25, 0xbc, 0x4f, 0x4a, 0x3b, 0x10, 0x0f, 0x81, 0x92, 0xe4, 0xda,
0x84, 0xad, 0x8b, 0xbb, 0x94, 0xc5, 0xf4, 0x4c, 0x25, 0xd2, 0x08, 0x97, 0xe0, 0x98, 0x0b,
0xbe, 0xe7, 0xaa, 0x40, 0x06, 0xfa, 0xe4, 0x79, 0xab, 0x76, 0x1f, 0xb6, 0x7f, 0x72, 0x48,
0x5c, 0x27, 0x8b, 0xab, 0xef, 0x13, 0xe1, 0x0c, 0xb1, 0x79, 0x7b, 0x6d, 0x8f, 0x0b, 0x90,
0x22, 0x7f, 0x2f, 0xa5, 0x71, 0xca, 0xb7, 0xc0, 0xbb, 0x31, 0x23, 0x03, 0x44, 0xd2, 0x51,
0x74, 0x08, 0x85, 0xad, 0x1e, 0xfb, 0xc3, 0xa2, 0xa1, 0xe1, 0x3e, 0x14, 0x0e, 0xf2, 0x0a,
0xb3, 0x9d, 0x74, 0x14, 0x50, 0xff, 0xfe, 0x95, 0xed, 0x02, 0x76, 0xe6, 0xf7, 0x0b, 0x32,
0x4e, 0x40, 0xb0, 0xd2, 0x67, 0x74, 0x92, 0x51, 0x1e, 0x54, 0x6f, 0x30, 0x6f, 0x58, 0x6a,
0xbb, 0x8a, 0x6c, 0xa6, 0x6d, 0x92, 0xe3, 0x3e, 0x0c, 0x33, 0x7c, 0xfc, 0x87, 0x12, 0xb8,
0x61, 0x70, 0xa6, 0x6c, 0x28, 0xad, 0xa2, 0x55, 0x81, 0x58, 0xd5, 0xc7, 0xb6, 0xd1, 0xdf,
0x47, 0x5d, 0x07, 0x1f, 0xed, 0xfd, 0x4e, 0x0f, 0x3c, 0xe3, 0x9d, 0xae, 0xeb, 0xf6, 0x3a,
0xb6, 0x0e, 0x5e, 0xc9, 0x9f, 0xc9, 0x5e, 0xbc, 0x37, 0xcf, 0x81, 0x04, 0x60, 0x26, 0xe4,
0x8b, 0x90, 0xdb, 0xf1, 0xc2, 0x66, 0x87, 0xd2, 0x29, 0x72, 0x01, 0xa6, 0xcd, 0x01, 0xdf,
0x9a, 0xfb, 0x4d, 0x62, 0xcb, 0x4d, 0x59, 0x18, 0xd2, 0x3f, 0x79, 0xf7, 0xaf, 0xda, 0x10,
0x66, 0xb6, 0x3e, 0x7e, 0x7b, 0xcb, 0xb6, 0xa0, 0xd7, 0xa8, 0x5b, 0xe7, 0x8e, 0xa0, 0x24,
0xf4, 0x55, 0x43, 0x00, 0xda, 0x86, 0x50, 0xec, 0x0a, 0x04, 0x27, 0xb1, 0x98, 0x40, 0x5c,
0xb1, 0xa5, 0x18, 0x87, 0xa9, 0x88, 0x87, 0x85, 0xe0, 0x89, 0xd5, 0xe2, 0x24, 0xef, 0x65,
0xac, 0x2c, 0xd1, 0x3a, 0xe7, 0x67, 0xee, 0xc4, 0xd6, 0x3a, 0x76, 0x2a, 0x55, 0x03, 0x5b,
0x0b, 0xde, 0x5e, 0x38, 0x5a, 0xb7, 0x7d, 0xb3, 0x82, 0x39, 0x5c, 0x98, 0xc3, 0x2f, 0x8d,
0x53, 0xa0, 0x41, 0x7d, 0xa8, 0x83, 0x47, 0x4a, 0xb0, 0x42, 0xc8, 0xeb, 0xf4, 0xfb, 0x9e,
0xe9, 0x82, 0xe3, 0xf6, 0x4d, 0x16, 0xe4, 0xd9, 0xd1, 0xca, 0x56, 0xae, 0x09, 0xe7, 0xcf,
0xaa, 0x25, 0x15, 0x91, 0xce, 0x15, 0xa9, 0x87, 0x50, 0x80, 0x38, 0xcd, 0x6a, 0x64, 0x4d,
0xb5, 0x55, 0x63, 0xc7, 0x9c, 0xb0, 0x52, 0xb0, 0x3d, 0x5a, 0x8b, 0x65, 0x19, 0x33, 0x43,
0xa2, 0x97, 0x20, 0xad, 0x79, 0xa6, 0xe8, 0x82, 0x06, 0x39, 0x45, 0x8b, 0x22, 0x35, 0x28,
0x72, 0x45, 0xc8, 0xca, 0xa4, 0xc3, 0x10, 0x20, 0x22, 0x83, 0x8f, 0x39, 0x49, 0x83, 0x72,
0x6d, 0xf4, 0x56, 0xfd, 0x55, 0x43, 0x60, 0x3d, 0x75, 0xa3, 0x4e, 0x14, 0x5b, 0xb8, 0xff,
0x4f, 0x17, 0xd9, 0x93, 0xd7, 0xc0, 0xaf, 0x5c, 0xb9, 0x65, 0xa5, 0x86, 0x8a, 0x9a, 0x35,
0x5d, 0x95, 0x30, 0x21, 0xc3, 0x38, 0x82, 0x05, 0x0b, 0xb8, 0x02, 0x20, 0xf1, 0x8a, 0x37,
0x15, 0x0a, 0xc2, 0x46, 0x8a, 0x16, 0x6f, 0x0d, 0x3a, 0x5b, 0x12, 0x6e, 0xee, 0xbf, 0xaf,
0xfb, 0x04, 0xe5, 0x34, 0xcc, 0x44, 0x2c, 0x3c, 0x22, 0x7c, 0x4f, 0xd7, 0xad, 0xe1, 0xe2,
0x12, 0xe6, 0xda, 0x69, 0x6f, 0x9c, 0xc8, 0x1f, 0xb9, 0x7e, 0x42, 0x20, 0x7d, 0x21, 0x0a,
0x0f, 0xb6, 0x16, 0x59, 0x01, 0x91, 0x16, 0xfe, 0xa4, 0x7b, 0xb6, 0x36, 0x43, 0x72, 0xbf,
0x33, 0x71, 0xb8, 0x5d, 0x8a, 0x4f, 0x91, 0xe0, 0x79, 0xb5, 0x40, 0xda, 0x9f, 0x02, 0xbe,
0x35, 0x60, 0xc0, 0xef, 0xc9, 0x2f, 0x42, 0xd3, 0xcd, 0xef, 0xde, 0x10, 0x71, 0x14, 0x8d,
0x86, 0x29, 0xcd, 0x31, 0x39, 0x90, 0xe0, 0x2d, 0x28, 0x97, 0xe4, 0xb3, 0xe5, 0xd7, 0x61,
0xe3, 0x2b, 0x21, 0xe7, 0xc5, 0x4b, 0xd6, 0xe9, 0xdb, 0x51, 0x03, 0xa2, 0x0e, 0x7c, 0x7e,
0x95, 0xa8, 0xf6, 0x8b, 0x95, 0x8f, 0x6e, 0xfd, 0x54, 0xfd, 0x28, 0x71, 0x4a, 0xfc, 0x75,
0x54, 0x19, 0x8c, 0xd3, 0x8a, 0x9b, 0x94, 0xcd, 0x33, 0x60, 0x80, 0x7a, 0xd4, 0x68, 0x38,
0x29, 0x0e, 0xf0, 0xc1, 0xeb, 0xac, 0xaf, 0xb1, 0xe6, 0xce, 0xbd, 0xd1, 0xfd, 0xbc, 0x23,
0x85, 0x8d, 0x97, 0xf4, 0xc9, 0xf9, 0xbd, 0x69, 0xd2, 0x0c, 0x60, 0x12, 0x05, 0x82, 0x6e,
0x5a, 0x6e, 0xfd, 0x55, 0xcc, 0xd8, 0xe6, 0xed, 0x54, 0xde, 0xdb, 0xcc, 0xf9, 0x85, 0x0b,
0xf6, 0x42, 0x39, 0x76, 0xde, 0xab, 0x08, 0xd7, 0x65, 0xe8, 0x19, 0xbd, 0x72, 0xec, 0x53,
0x7d, 0xc8, 0xa6, 0x00, 0xb3, 0x3e, 0x5b, 0x7d, 0xa0, 0x7b, 0xaa, 0x6e, 0xc5, 0x45, 0x12,
0xe3, 0xac, 0x02, 0x1c, 0x01, 0xb8, 0x2b, 0x2b, 0xd6, 0xf8, 0x2e, 0x96, 0x3a, 0x5e, 0x6e,
0xda, 0xf9, 0x6c, 0xac, 0x36, 0xf8, 0xcd, 0xef, 0x05, 0x8d, 0x8f, 0xe7, 0x6c, 0x39, 0x24,
0xb3, 0x8d, 0xed, 0xd1, 0x70, 0xa6, 0x20, 0x1e, 0x2b, 0x1d, 0x2c, 0x40, 0x16, 0xd6, 0x23,
0xb0, 0x99, 0xaa, 0x74, 0x31, 0xbe, 0xdc, 0x28, 0xd4, 0x64, 0xfa, 0xd2, 0x8d, 0xdb, 0xa1,
0x32, 0xaf, 0xdc, 0xb1, 0x71, 0xb3, 0x4d, 0x0a, 0x3a, 0x3a, 0x53, 0x11, 0x8c, 0x11, 0x8c,
0xe7, 0xd5, 0xdb, 0xdd, 0x67, 0xb8, 0x1a, 0x39, 0x0e, 0xf6, 0x69, 0xd8, 0x1b, 0xcb, 0xe5,
0xc5, 0xa6, 0x3d, 0x3b, 0xfe, 0xe1, 0x05, 0x48, 0x83, 0x67, 0x7f, 0xf1, 0x9c, 0x70, 0x7e,
0x70, 0x5c, 0xc4, 0xd3, 0x78, 0x8b, 0x80, 0x87, 0xf5, 0x94, 0x2d, 0x0a, 0xbf, 0x82, 0x13,
0xad, 0x36, 0x10, 0x0a, 0x60, 0xaa, 0xc4, 0xa3, 0xcd, 0xf1, 0xa9, 0xa1, 0x49, 0xf5, 0x41,
0x14, 0xd6, 0xd1, 0xa7, 0xe0, 0x50, 0xce, 0xe2, 0x76, 0xbe, 0x09, 0xc4, 0x3a, 0x68, 0xc5,
0x8a, 0x1f, 0x8e, 0xd0, 0x4d, 0x90, 0x92, 0xc8, 0x3b, 0x63, 0xae, 0xc2, 0xfe, 0x77, 0x8c,
0x4b, 0xa6, 0x6c, 0x04, 0xff, 0x62, 0xe1, 0x32, 0x04, 0xb8, 0xfd, 0xb3, 0x34, 0x47, 0x85,
0x32, 0x6b, 0x50, 0xce, 0xcf, 0x4f, 0x0f, 0x72, 0x41, 0x09, 0x7f, 0xde, 0x5c, 0xe7, 0x08,
0xdf, 0x63, 0x09, 0x89, 0xd1, 0x23, 0xb6, 0xe3, 0xbc, 0xff, 0xe4, 0x88, 0x61, 0x67, 0x8e,
0x4a, 0xb6, 0x86, 0x08, 0x33, 0xad, 0xac, 0x9f, 0xf3, 0x37, 0xbd, 0xcc, 0xd6, 0x0e, 0x3e,
0x4e, 0x4f, 0xc9, 0xff, 0xc8, 0xf6, 0xd8, 0x2a, 0x43, 0x3d, 0x79, 0xf2, 0x5d, 0x87, 0x33,
0x1d, 0xf4, 0xfd, 0x80, 0x2c, 0x4f, 0xc4, 0xa5, 0x3a, 0x2f, 0x51, 0xb1, 0x19, 0xf8, 0xed,
0xe0, 0xc9, 0x6c, 0x82, 0x2d, 0x43, 0xdd, 0x71, 0x27, 0x32, 0x8b, 0x51, 0x3d, 0xbc, 0x83,
0x6b, 0xa8, 0xda, 0x2b, 0xbb, 0xb0, 0xba, 0x5b, 0x30, 0x4f, 0x44, 0xad, 0x99, 0xb7, 0x47,
0x35, 0x6f, 0x1f, 0xbe, 0x5f, 0x24, 0x4e, 0xba, 0x92, 0x89, 0xc8, 0xb6, 0x45, 0x12, 0x19,
0xee, 0xe7, 0xd8, 0x74, 0xb3, 0x33, 0x41, 0x39, 0x26, 0x4c, 0xc3, 0xb0, 0x22, 0x1e, 0xee,
0xd0, 0xfb, 0xc6, 0xa3, 0x7d, 0xaa, 0x7d, 0xa1, 0x51, 0x98, 0xe8, 0xcc, 0x58, 0x39, 0x22,
0x1e, 0xe7, 0xf0, 0xb4, 0xd3, 0x7c, 0xa4, 0xa6, 0x10, 0xba, 0x2f, 0x41, 0xd6, 0x17, 0x95,
0x76, 0xe1, 0xbb, 0xec, 0x43, 0x99, 0x87, 0xd4, 0x13, 0x9b, 0x85, 0x4f, 0x44, 0x32, 0x5a,
0xe0, 0x9a, 0xee, 0x29, 0x15, 0x45, 0x05, 0xf7, 0xe4, 0xc9, 0x4d, 0x6b, 0x45, 0xad, 0x1f,
0x13, 0x06, 0x29, 0xb4, 0x2b, 0x74, 0x83, 0xe1, 0xdb, 0x3d, 0x99, 0x28, 0xbd, 0x4f, 0xfb,
0x0d, 0x03, 0x4d, 0x79, 0x09, 0x7f, 0x12, 0x91, 0xe9, 0x69, 0x40, 0x84, 0xc7, 0x10, 0xd5,
0xce, 0xae, 0xbb, 0xa5, 0xb2, 0x35, 0xdb, 0x24, 0xa4, 0x0e, 0xe4, 0x6f, 0x80, 0xb4, 0xb6,
0x94, 0xf7, 0x51, 0x5b, 0x0c, 0x5b, 0xae, 0x3f, 0xa5, 0x17, 0xe0, 0x9c, 0xd1, 0x05, 0x31,
0x05, 0xc4, 0x14, 0xdd, 0xde, 0x6f, 0x39, 0xa1, 0x9a, 0x46, 0x3d, 0x68, 0x3c, 0xfe, 0x04,
0x8e, 0xc2, 0x11, 0x9d, 0xc2, 0x3a, 0xaa, 0xcf, 0x22, 0x26, 0x54, 0xcb, 0x8d, 0x47, 0x61,
0x9e, 0xf4, 0x2e, 0xe7, 0x3c, 0xe6, 0xf0, 0xd6, 0x1a, 0xe5, 0x18, 0xbd, 0x9f, 0xa4, 0x3e,
0x47, 0xdb, 0x85, 0xe0, 0x8c, 0xbf, 0xdd, 0x19, 0x91, 0x81, 0x80, 0x63, 0x44, 0x0a, 0x96,
0xae, 0xde, 0x1f, 0xbc, 0xdb, 0x15, 0x89, 0x71, 0x60, 0x23, 0xc4, 0x0a, 0x96, 0xae, 0xbf,
0xfc, 0x7a, 0x76, 0x4f, 0x1c, 0x9b, 0xb4, 0xcb, 0x14, 0x8b, 0x94, 0x8b, 0x94, 0xaa, 0xd6,
0x0f, 0x7d, 0x78, 0x72, 0x47, 0x0c, 0x9a, 0x97, 0xac, 0xbb, 0xf4, 0x6a, 0x56, 0x0f, 0x7d,
0x59, 0x30, 0xc3, 0x04, 0x6b, 0x54, 0x0b, 0x75, 0x49, 0x10, 0xa2, 0xa7, 0xad, 0xd8, 0x13,
0x85, 0x88, 0x73, 0x45, 0xe9, 0x31, 0xc1, 0x00, 0x82, 0x67, 0x4c, 0xfb, 0x74, 0x6a, 0x56,
0x2e, 0xbf, 0xdd, 0x19, 0x91, 0x81, 0x80, 0x82, 0x86, 0x6f, 0x5c, 0x3a, 0xf6, 0x4f, 0x1c,
0xba, 0xf6, 0x4f, 0xfd, 0x59, 0x11, 0x81, 0x61, 0x21, 0xa1, 0xc0, 0x02, 0x86, 0x6f, 0x3d,
0xf8, 0x53, 0x24, 0xca, 0xf7, 0x6c, 0x5a, 0x36, 0xcf, 0xfd, 0x59, 0x11, 0xa0, 0xa3, 0xc4,
0x0a, 0x96, 0x8f, 0x9c, 0xba, 0xd7, 0x0d, 0x98, 0xb2, 0xc7, 0xed, 0x58, 0x32, 0xc7, 0xed,
0x39, 0xf0, 0x43, 0x04, 0x6b, 0x54, 0x2a, 0xb7, 0xec, 0x5a, 0x36, 0xee, 0x3f, 0xfc, 0x7a,
0x76, 0x6e, 0x5e, 0x1f, 0x9d, 0x99, 0x91, 0x81, 0x80, 0x82, 0x86, 0x6f, 0x5c, 0x1b, 0x95,
0x89, 0x90, 0xa2, 0xa7, 0xcc, 0x1a, 0x97, 0xac, 0xbb, 0xf4, 0x6a, 0x37, 0xec, 0x3b, 0xf4,
0x6a, 0x37, 0xec, 0x3b, 0xf4, 0x4b, 0xf5, 0x49, 0xf1, 0x60, 0x23, 0xa5, 0xa9, 0xb1, 0xc1,
0xe1, 0x21, 0xa1, 0xa1, 0xc0, 0xe3, 0x25, 0xa9, 0xb1, 0xe0, 0x42, 0xe7, 0x4c, 0xfb, 0x74,
0x6a, 0x37, 0xec, 0x5a, 0x17, 0xac, 0xbb, 0xd5, 0x28, 0xd2, 0x07, 0x6d, 0x58, 0x13, 0x85,
0x69, 0x31, 0xe0, 0x42, 0xe7, 0x4c, 0xfb, 0x55, 0x28, 0xd2, 0x07, 0x8c, 0x7b, 0x74, 0x4b,
0x14, 0xaa, 0xd6, 0x2e, 0xde, 0x3e, 0xfe, 0x7e, 0x5f, 0x1d, 0xb8, 0xf2, 0x47, 0x0c, 0x7b,
0x55, 0x09, 0x90, 0x83, 0x65, 0x48, 0x12, 0x87, 0x6d, 0x39, 0xf0, 0x62, 0x46, 0x0e, 0x9e,
0x9f, 0xbc, 0xfa, 0x57, 0x2c, 0xbb, 0xd5, 0x09, 0x71, 0x60, 0x5b, 0x08, 0xf7, 0x2b,
};
#endif

View file

@ -0,0 +1,397 @@
/*
* Copyright (c) 2022 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#define DT_DRV_COMPAT pixart_pmw33xx
#include <drivers/spi.h>
#include <errno.h>
#include <device.h>
#include <drivers/gpio.h>
#include <sys/util.h>
#include <sys/byteorder.h>
#include <kernel.h>
#include <drivers/sensor.h>
#include <sys/__assert.h>
#include <logging/log.h>
#ifdef CONFIG_PMW33XX_3389
#include <pmw3389_srom.h>
#elif CONFIG_PMW33XX_3360
#include <pmw3360_srom.h>
#endif
#include "pmw33xx.h"
LOG_MODULE_REGISTER(PMW33XX, CONFIG_SENSOR_LOG_LEVEL);
#define PMW33XX_PID COND_CODE_1(CONFIG_PMW33XX_3389, (PMW33XX_3389_PID), (PMW33XX_3360_PID))
#define PMW33XX_CPI_MAX \
COND_CODE_1(CONFIG_PMW33XX_3389, (PMW33XX_3389_CPI_MAX), (PMW33XX_3360_CPI_MAX))
#define PMW33XX_CPI_MIN \
COND_CODE_1(CONFIG_PMW33XX_3389, (PMW33XX_3389_CPI_MIN), (PMW33XX_3360_CPI_MIN))
struct pmw33xx_motion_burst {
uint8_t motion;
uint8_t observation;
int16_t dx;
int16_t dy;
} __attribute__((packed));
static inline int pmw33xx_cs_select(const struct pmw33xx_gpio_dt_spec *cs_gpio_cfg,
const uint8_t value) {
return gpio_pin_set(cs_gpio_cfg->port, cs_gpio_cfg->pin, value);
}
static int pmw33xx_access(const struct device *dev, const uint8_t reg, uint8_t *value) {
struct pmw33xx_data *data = dev->data;
const struct pmw33xx_config *cfg = dev->config;
const struct spi_config *spi_cfg = &cfg->bus_cfg.spi_cfg->spi_conf;
const struct pmw33xx_gpio_dt_spec *cs_gpio_cfg = &cfg->bus_cfg.spi_cfg->cs_spec;
uint8_t access[1] = {reg};
struct spi_buf_set tx = {
.buffers =
&(struct spi_buf){
.buf = access,
.len = 1,
},
.count = 1,
};
uint8_t result[1];
if (value != NULL) {
result[0] = *value;
}
struct spi_buf_set rx = {
.buffers =
&(struct spi_buf){
.buf = result,
.len = 1,
},
.count = 1,
};
pmw33xx_cs_select(cs_gpio_cfg, 0);
int err = spi_write(data->bus, spi_cfg, &tx);
k_sleep(K_USEC(120)); // Tsrad
if (err) {
pmw33xx_cs_select(cs_gpio_cfg, 1);
return err;
}
if ((reg & PMW33XX_WR_MASK))
err = spi_write(data->bus, spi_cfg, &rx);
else
err = spi_read(data->bus, spi_cfg, &rx);
pmw33xx_cs_select(cs_gpio_cfg, 1);
k_sleep(K_USEC(160));
if ((reg & PMW33XX_WR_MASK) == 0 && value != NULL)
*value = result[0];
return err;
}
static int pmw33xx_read_reg(const struct device *dev, const uint8_t reg, uint8_t *value) {
return pmw33xx_access(dev, reg & PMW33XX_RD_MASK, value);
}
static int pmw33xx_write_reg(const struct device *dev, const uint8_t reg, const uint8_t value) {
uint8_t v = value;
return pmw33xx_access(dev, reg | PMW33XX_WR_MASK, &v);
}
static int pmw33xx_write_srom(const struct device *dev) {
struct pmw33xx_data *data = dev->data;
const struct pmw33xx_config *cfg = dev->config;
const struct spi_config *spi_cfg = &cfg->bus_cfg.spi_cfg->spi_conf;
const struct pmw33xx_gpio_dt_spec *cs_gpio_cfg = &cfg->bus_cfg.spi_cfg->cs_spec;
uint8_t access[1] = {PMW33XX_REG_SROM_BURST | PMW33XX_WR_MASK};
struct spi_buf_set tx = {
.buffers =
&(struct spi_buf){
.buf = access,
.len = 1,
},
.count = 1,
};
pmw33xx_write_reg(dev, PMW33XX_REG_SROM_EN, PMW33XX_SROM_DWNLD_CMD);
k_sleep(K_USEC(15));
pmw33xx_write_reg(dev, PMW33XX_REG_SROM_EN, PMW33XX_SROM_DWNLD_START_CMD);
pmw33xx_cs_select(cs_gpio_cfg, 0);
int err = spi_write(data->bus, spi_cfg, &tx);
k_sleep(K_USEC(15));
if (err) {
pmw33xx_cs_select(cs_gpio_cfg, 1);
return err;
}
for (uint16_t i = 0; i < sizeof(SROM); i++) {
access[0] = SROM[i];
err = spi_write(data->bus, spi_cfg, &tx);
k_sleep(K_USEC(15));
if (err) {
pmw33xx_cs_select(cs_gpio_cfg, 1);
return err;
}
}
pmw33xx_cs_select(cs_gpio_cfg, 1);
k_sleep(K_MSEC(2)); // Tbexit
return err;
}
static int pmw33xx_read_motion_burst(const struct device *dev, struct pmw33xx_motion_burst *burst) {
struct pmw33xx_data *data = dev->data;
const struct pmw33xx_config *cfg = dev->config;
const struct spi_config *spi_cfg = &cfg->bus_cfg.spi_cfg->spi_conf;
const struct pmw33xx_gpio_dt_spec *cs_gpio_cfg = &cfg->bus_cfg.spi_cfg->cs_spec;
uint8_t access[1] = {PMW33XX_REG_BURST};
struct spi_buf_set tx = {
.buffers =
&(struct spi_buf){
.buf = access,
.len = 1,
},
.count = 1,
};
struct spi_buf_set rx = {
.buffers =
&(struct spi_buf){
.buf = (uint8_t *)burst,
.len = sizeof(struct pmw33xx_motion_burst),
},
.count = 1,
};
pmw33xx_cs_select(cs_gpio_cfg, 0);
int err = spi_write(data->bus, spi_cfg, &tx);
k_sleep(K_USEC(35)); // tsrad motbr
if (err) {
pmw33xx_cs_select(cs_gpio_cfg, 1);
return err;
}
err = spi_read(data->bus, spi_cfg, &rx);
pmw33xx_cs_select(cs_gpio_cfg, 1);
#ifdef CONFIG_PMW33XX_TRIGGER
pmw33xx_reset_motion(dev);
#endif
return err;
}
#ifdef CONFIG_PMW33XX_TRIGGER
void pmw33xx_reset_motion(const struct device *dev) {
// reset motswk interrupt
pmw33xx_read_reg(dev, PMW33XX_REG_MOTION, NULL);
}
#endif
int pmw33xx_spi_init(const struct device *dev) {
const struct pmw33xx_config *cfg = dev->config;
const struct pmw33xx_gpio_dt_spec *cs_gpio_cfg = &cfg->bus_cfg.spi_cfg->cs_spec;
int err;
err = gpio_pin_configure(cs_gpio_cfg->port, cs_gpio_cfg->pin, GPIO_OUTPUT_ACTIVE);
if (err) {
LOG_ERR("could configure cs pin %d", err);
return -EIO;
}
return 0;
}
static int pmw33xx_sample_fetch(const struct device *dev, enum sensor_channel chan) {
struct pmw33xx_data *data = dev->data;
struct pmw33xx_motion_burst burst;
if (chan != SENSOR_CHAN_ALL && chan != SENSOR_CHAN_POS_DX && chan != SENSOR_CHAN_POS_DY)
return -ENOTSUP;
int err = pmw33xx_read_motion_burst(dev, &burst);
if (err) {
return err;
}
if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_POS_DX)
data->dx += burst.dx;
if (chan == SENSOR_CHAN_ALL || chan == SENSOR_CHAN_POS_DY)
data->dy += burst.dy;
return 0;
}
static int pmw33xx_channel_get(const struct device *dev, enum sensor_channel chan,
struct sensor_value *val) {
struct pmw33xx_data *data = dev->data;
switch (chan) {
case SENSOR_CHAN_POS_DX:
val->val1 = data->dx;
data->dx = 0;
break;
case SENSOR_CHAN_POS_DY:
val->val1 = data->dy;
data->dy = 0;
break;
default:
return -ENOTSUP;
}
return 0;
}
static const struct sensor_driver_api pmw33xx_driver_api = {
#ifdef CONFIG_PMW33XX_TRIGGER
.trigger_set = pmw33xx_trigger_set,
#endif
// eventually implement this to allow setting cpi from the driver api maybe
// .attr_set = pmw33xx_attr_set,
.sample_fetch = pmw33xx_sample_fetch,
.channel_get = pmw33xx_channel_get,
};
static int pmw33xx_set_cpi(const struct device *dev, uint16_t cpi) {
#ifdef CONFIG_PMW33XX_3360
if (cpi > PMW33XX_CPI_MIN && cpi < PMW33XX_CPI_MAX)
return pmw33xx_write_reg(dev, PMW33XX_3360_REG_CPI,
((cpi / 100) - 1)); /* 100-12000, 100 cpi LSb */
#elif CONFIG_PMW33XX_3389
if (cpi > PMW33XX_CPI_MIN && cpi < PMW33XX_CPI_MAX) {
cpi /= 50;
int err =
pmw33xx_write_reg(dev, PMW33XX_3389_REG_CPI_L, cpi & 0xFF); /* 50-16000, 50 cpi LSb */
if (err) {
return err;
}
return pmw33xx_write_reg(dev, PMW33XX_3389_REG_CPI_H, cpi >> 8); /* 50-16000, 50 cpi LSb */
}
#endif
return -ENOTSUP;
}
static int pmw33xx_init_chip(const struct device *dev) {
const struct pmw33xx_config *const config = dev->config;
const struct pmw33xx_gpio_dt_spec *cs_gpio_cfg = &config->bus_cfg.spi_cfg->cs_spec;
pmw33xx_cs_select(cs_gpio_cfg, 1);
k_sleep(K_MSEC(1));
int err = pmw33xx_write_reg(dev, PMW33XX_REG_PWR_UP_RST, PMW33XX_RESET_CMD);
if (err) {
LOG_ERR("could not reset %d", err);
return -EIO;
}
uint8_t pid = 0x0;
err = pmw33xx_read_reg(dev, PMW33XX_REG_PID, &pid);
if (err) {
LOG_ERR("could not reset %d", err);
return -EIO;
}
if (pid != PMW33XX_PID) {
LOG_ERR("pid does not match expected: got (%x), expected(%x)", pid, PMW33XX_PID);
return -EIO;
}
pmw33xx_write_reg(dev, PMW33XX_REG_CONFIG2,
config->disable_rest ? 0x00 : PMW33XX_RESTEN); // set rest enable
err = pmw33xx_write_srom(dev);
if (err) {
LOG_ERR("could not upload srom %d", err);
return -EIO;
}
uint8_t srom_run = 0x0;
err = pmw33xx_read_reg(dev, PMW33XX_REG_OBSERVATION, &srom_run);
if (err) {
LOG_ERR("could not check srom status %d", err);
return -EIO;
}
if (!(srom_run & PMW33XX_SROM_RUN)) {
LOG_ERR("srom status invalid %d", srom_run);
return -EIO;
}
uint8_t srom_id = 0x0;
err = pmw33xx_read_reg(dev, PMW33XX_REG_SROM_ID, &srom_id);
if (err) {
LOG_ERR("could not check srom id %d", err);
return -EIO;
}
if (!srom_id) {
LOG_ERR("srom id invalid %d", srom_id);
return -EIO;
}
pmw33xx_write_reg(dev, PMW33XX_REG_BURST, 0x01);
struct pmw33xx_motion_burst val;
pmw33xx_read_motion_burst(dev, &val); // read and throwout initial motion data
if (config->cpi > PMW33XX_CPI_MIN && config->cpi < PMW33XX_CPI_MAX)
return pmw33xx_set_cpi(dev, config->cpi);
return 0;
}
static int pmw33xx_init(const struct device *dev) {
const struct pmw33xx_config *const config = dev->config;
struct pmw33xx_data *data = dev->data;
data->bus = device_get_binding(config->bus_name);
if (!data->bus) {
LOG_DBG("master not found: %s", log_strdup(config->bus_name));
return -EINVAL;
}
config->bus_init(dev);
if (pmw33xx_init_chip(dev) < 0) {
LOG_DBG("failed to initialize chip");
return -EIO;
}
#ifdef CONFIG_PMW33XX_TRIGGER
if (pmw33xx_init_interrupt(dev) < 0) {
LOG_DBG("Failed to initialize interrupt!");
return -EIO;
}
#endif
return 0;
}
#define PMW33XX_DATA_SPI(n) \
{ .cs_ctrl = {}, }
#define PMW33XX_SPI_CFG(n) \
(&(struct pmw33xx_spi_cfg){ \
.spi_conf = \
{ \
.frequency = DT_INST_PROP(n, spi_max_frequency), \
.operation = \
(SPI_WORD_SET(8) | SPI_OP_MODE_MASTER | SPI_MODE_CPOL | SPI_MODE_CPHA), \
.slave = DT_INST_REG_ADDR(n), \
}, \
.cs_spec = PMW33XX_GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(n), cs_gpios, 0), \
})
#define PMW33XX_GPIO_DT_SPEC_GET_BY_IDX(node_id, prop, idx) \
{ \
.port = DEVICE_DT_GET(DT_GPIO_CTLR_BY_IDX(node_id, prop, idx)), \
.pin = DT_GPIO_PIN_BY_IDX(node_id, prop, idx), \
.dt_flags = DT_GPIO_FLAGS_BY_IDX(node_id, prop, idx), \
}
#define PMW33XX_CONFIG_SPI(n) \
{ \
.bus_name = DT_INST_BUS_LABEL(n), .bus_init = pmw33xx_spi_init, \
.bus_cfg = {.spi_cfg = PMW33XX_SPI_CFG(n)}, \
.disable_rest = DT_INST_NODE_HAS_PROP(n, disable_rest), \
COND_CODE_0(DT_INST_NODE_HAS_PROP(n, cpi), (0), (DT_INST_PROP(n, cpi))) \
COND_CODE_1(CONFIG_PMW33XX_TRIGGER, \
(, PMW33XX_GPIO_DT_SPEC_GET_BY_IDX(DT_DRV_INST(n), motswk_gpios, 0)), ()) \
}
#define PMW33XX_INST(n) \
static struct pmw33xx_data pmw33xx_data_##n = PMW33XX_DATA_SPI(n); \
static const struct pmw33xx_config pmw33xx_cfg_##n = PMW33XX_CONFIG_SPI(n); \
DEVICE_DT_INST_DEFINE(n, pmw33xx_init, device_pm_control_nop, &pmw33xx_data_##n, \
&pmw33xx_cfg_##n, POST_KERNEL, CONFIG_SENSOR_INIT_PRIORITY, \
&pmw33xx_driver_api);
DT_INST_FOREACH_STATUS_OKAY(PMW33XX_INST)

View file

@ -0,0 +1,150 @@
/*
* Copyright (c) 2022 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#ifndef ZEPHYR_DRIVERS_SENSOR_PIXART_PMW33XX_H_
#define ZEPHYR_DRIVERS_SENSOR_PIXART_PMW33XX_H_
#include <drivers/sensor.h>
#include <zephyr/types.h>
#include <drivers/gpio.h>
#include <sys/util.h>
#include <drivers/spi.h>
#define PMW33XX_WR_MASK 0x80
#define PMW33XX_RD_MASK 0x7F
#define PMW33XX_3389_PID 0x47
#define PMW33XX_3360_PID 0x42
#define PMW33XX_REV 0x01
/* General Registers */
#define PMW33XX_REG_PID 0x00
#define PMW33XX_REG_REV_ID 0x01
#define PMW33XX_REG_PWR_UP_RST 0x3A
/* Motion Registers */
#define PMW33XX_REG_MOTION 0x02
#define PMW33XX_REG_DX_L 0x03
#define PMW33XX_REG_DX_H 0x04
#define PMW33XX_REG_DY_L 0x05
#define PMW33XX_REG_DY_H 0x06
#define PMW33XX_REG_BURST 0x50
/* Motion bits */
#define PMW33XX_MOTION (1 << 8)
#define PMW33XX_OPMODE_RUN (0)
#define PMW33XX_OPMODE_REST1 (0b01 << 1)
#define PMW33XX_OPMODE_REST2 (0b10 << 1)
#define PMW33XX_OPMODE_REST3 (0b11 << 1)
/* SROM Registers */
#define PMW33XX_REG_SROM_EN 0x13
#define PMW33XX_REG_SROM_ID 0x2A
#define PMW33XX_REG_SROM_BURST 0x62
/* SROM CMDs */
#define PMW33XX_SROM_CRC_CMD 0x15
#define PMW33XX_SROM_DWNLD_CMD 0x1D
#define PMW33XX_SROM_DWNLD_START_CMD 0x18
/* CPI Registers */
#define PMW33XX_3360_REG_CPI 0x0F
#define PMW33XX_3389_REG_CPI_L 0x0E
#define PMW33XX_3389_REG_CPI_H 0x0F
/* Config Registers */
#define PMW33XX_REG_CONFIG2 0x10
#define PMW33XX_REG_OBSERVATION 0x24
#define PMW33XX_REG_DOUT_L 0x25
#define PMW33XX_REG_DOUT_H 0x26
/* Config2 Bits */
#define PMW33XX_RESTEN 0x20
#define PMW33XX_RPT_MOD 0x04
/* Observation Bits */
#define PMW33XX_SROM_RUN 0x40
/* power up reset cmd */
#define PMW33XX_RESET_CMD 0x5A
/* cpi max and min values */
#define PMW33XX_3389_CPI_MIN 50
#define PMW33XX_3389_CPI_MAX 16000
#define PMW33XX_3360_CPI_MIN 100
#define PMW33XX_3360_CPI_MAX 12000
struct pmw33xx_gpio_dt_spec {
const struct device *port;
gpio_pin_t pin;
gpio_dt_flags_t dt_flags;
};
struct pmw33xx_spi_cfg {
struct spi_config spi_conf;
struct pmw33xx_gpio_dt_spec cs_spec;
};
union pmw33xx_bus_cfg {
struct pmw33xx_spi_cfg *spi_cfg;
};
struct pmw33xx_config {
char *bus_name;
int (*bus_init)(const struct device *dev);
const union pmw33xx_bus_cfg bus_cfg;
bool disable_rest;
int cpi;
#if CONFIG_PMW33XX_TRIGGER
struct pmw33xx_gpio_dt_spec motswk_spec;
#endif // CONFIG_PMW33XX_TRIGGER
};
struct pmw33xx_data;
struct pmw33xx_transfer_function {
int (*read_data)(const struct device *dev, int16_t *value);
};
struct pmw33xx_data {
const struct device *bus;
struct spi_cs_control cs_ctrl;
int16_t dx;
int16_t dy;
const struct pmw33xx_transfer_function *hw_tf;
#ifdef CONFIG_PMW33XX_TRIGGER
struct gpio_callback motswk_gpio_cb;
const struct device *dev;
sensor_trigger_handler_t handler;
const struct sensor_trigger *trigger;
#if defined(CONFIG_PMW33XX_TRIGGER_OWN_THREAD)
K_THREAD_STACK_MEMBER(thread_stack, CONFIG_PMW33XX_THREAD_STACK_SIZE);
struct k_sem gpio_sem;
struct k_thread thread;
#elif defined(CONFIG_PMW33XX_TRIGGER_GLOBAL_THREAD)
struct k_work work;
#endif
#endif /* CONFIG_PMW33XX_TRIGGER */
};
int pmw33xx_spi_init(const struct device *dev);
#ifdef CONFIG_PMW33XX_TRIGGER
int pmw33xx_trigger_set(const struct device *dev, const struct sensor_trigger *trig,
sensor_trigger_handler_t handler);
int pmw33xx_init_interrupt(const struct device *dev);
void pmw33xx_reset_motion(const struct device *dev);
#endif
#endif /* ZEPHYR_DRIVERS_SENSOR_PIXART_PMW33XX_H_ */

View file

@ -0,0 +1,127 @@
/*
* Copyright (c) 2022 The ZMK Contributors
*
* SPDX-License-Identifier: MIT
*/
#define DT_DRV_COMPAT pixart_pmw33xx
#include <device.h>
#include <drivers/gpio.h>
#include <sys/util.h>
#include <kernel.h>
#include <drivers/sensor.h>
#include "pmw33xx.h"
// extern struct pmw33xx_data pmw33xx_driver;
#include <logging/log.h>
LOG_MODULE_DECLARE(PMW33XX, CONFIG_SENSOR_LOG_LEVEL);
static inline void setup_int(const struct device *dev, bool enable) {
struct pmw33xx_data *data = dev->data;
const struct pmw33xx_config *cfg = dev->config;
gpio_pin_configure(cfg->motswk_spec.port, cfg->motswk_spec.pin, cfg->motswk_spec.dt_flags);
if (gpio_pin_interrupt_configure(cfg->motswk_spec.port, cfg->motswk_spec.pin,
enable ? GPIO_INT_EDGE_TO_ACTIVE : GPIO_INT_DISABLE)) {
LOG_WRN("Unable to set MOTSWK GPIO interrupt");
}
}
static void pmw33xx_motswk_gpio_callback(const struct device *dev, struct gpio_callback *cb,
uint32_t pins) {
struct pmw33xx_data *drv_data = CONTAINER_OF(cb, struct pmw33xx_data, motswk_gpio_cb);
LOG_DBG("");
setup_int(drv_data->dev, false);
#if defined(CONFIG_PMW33XX_TRIGGER_OWN_THREAD)
k_sem_give(&drv_data->gpio_sem);
#elif defined(CONFIG_PMW33XX_TRIGGER_GLOBAL_THREAD)
k_work_submit(&drv_data->work);
#endif
}
static void pmw33xx_thread_cb(const struct device *dev) {
struct pmw33xx_data *drv_data = dev->data;
LOG_DBG("%p", drv_data->handler);
drv_data->handler(dev, drv_data->trigger);
// Enable once the wall/spam of interrupts is solved
setup_int(dev, true);
}
#ifdef CONFIG_PMW33XX_TRIGGER_OWN_THREAD
static void pmw33xx_thread(int dev_ptr, int unused) {
const struct device *dev = INT_TO_POINTER(dev_ptr);
struct pmw33xx_data *drv_data = dev->data;
ARG_UNUSED(unused);
while (1) {
k_sem_take(&drv_data->gpio_sem, K_FOREVER);
pmw33xx_thread_cb(dev);
}
}
#endif
#ifdef CONFIG_PMW33XX_TRIGGER_GLOBAL_THREAD
static void pmw33xx_work_cb(struct k_work *work) {
struct pmw33xx_data *drv_data = CONTAINER_OF(work, struct pmw33xx_data, work);
LOG_DBG(" ");
pmw33xx_thread_cb(drv_data->dev);
}
#endif
int pmw33xx_trigger_set(const struct device *dev, const struct sensor_trigger *trig,
sensor_trigger_handler_t handler) {
struct pmw33xx_data *drv_data = dev->data;
setup_int(dev, false);
k_msleep(5);
drv_data->trigger = trig;
drv_data->handler = handler;
setup_int(dev, true);
// reset motion on int setup
pmw33xx_reset_motion(dev);
return 0;
}
int pmw33xx_init_interrupt(const struct device *dev) {
struct pmw33xx_data *drv_data = dev->data;
const struct pmw33xx_config *drv_cfg = dev->config;
drv_data->dev = dev;
/* setup gpio interrupt */
gpio_init_callback(&drv_data->motswk_gpio_cb, pmw33xx_motswk_gpio_callback,
BIT(drv_cfg->motswk_spec.pin));
int err = gpio_add_callback(drv_cfg->motswk_spec.port, &drv_data->motswk_gpio_cb);
if (err < 0) {
LOG_DBG("Failed to set MOTSWK callback!");
return -EIO;
}
#if defined(CONFIG_PMW33XX_TRIGGER_OWN_THREAD)
k_sem_init(&drv_data->gpio_sem, 0, UINT_MAX);
k_thread_create(&drv_data->thread, drv_data->thread_stack, CONFIG_PMW33XX_THREAD_STACK_SIZE,
(k_thread_entry_t)pmw33xx_thread, dev, 0, NULL,
K_PRIO_COOP(CONFIG_PMW33XX_THREAD_PRIORITY), 0, K_NO_WAIT);
#elif defined(CONFIG_PMW33XX_TRIGGER_GLOBAL_THREAD)
k_work_init(&drv_data->work, pmw33xx_work_cb);
#endif
return 0;
}

View file

@ -0,0 +1,28 @@
# Copyright (c) 2022 The ZMK Contributors
# SPDX-License-Identifier: MIT
description: |
Sensor driver for the pixart PMW33XX optical mouse sensor supports 3360 built in, and 3389 with external srom
compatible: "pixart,pmw33xx"
include: spi-device.yaml
properties:
label:
type: string
required: true
cs-gpios:
type: phandle-array
required: true
description: chip select pin for the sensor
motswk-gpios:
type: phandle-array
required: false
description: interrupt pin for motion
cpi:
type: int
description: mouse cpi
required: false
disable-rest:
type: boolean
description: disables mouse rest mode, will decrease battery life
required: false