2323 */
2424
2525#include "hid-ids.h"
26+ #include <asm/unaligned.h>
2627#include <linux/delay.h>
2728#include <linux/device.h>
2829#include <linux/hid.h>
@@ -96,11 +97,23 @@ static const u8 JC_USB_RESET = 0x06;
9697static const u8 JC_USB_PRE_HANDSHAKE = 0x91 ;
9798static const u8 JC_USB_SEND_UART = 0x92 ;
9899
99- /* SPI storage addresses of factory calibration data */
100- static const u16 JC_CAL_DATA_START = 0x603d ;
101- static const u16 JC_CAL_DATA_END = 0x604e ;
102- #define JC_CAL_DATA_SIZE (JC_CAL_DATA_END - JC_CAL_DATA_START + 1)
100+ /* Magic value denoting presence of user calibration */
101+ static const u16 JC_CAL_USR_MAGIC_0 = 0xB2 ;
102+ static const u16 JC_CAL_USR_MAGIC_1 = 0xA1 ;
103+ static const u8 JC_CAL_USR_MAGIC_SIZE = 2 ;
104+
105+ /* SPI storage addresses of user calibration data */
106+ static const u16 JC_CAL_USR_LEFT_MAGIC_ADDR = 0x8010 ;
107+ static const u16 JC_CAL_USR_LEFT_DATA_ADDR = 0x8012 ;
108+ static const u16 JC_CAL_USR_LEFT_DATA_END = 0x801A ;
109+ static const u16 JC_CAL_USR_RIGHT_MAGIC_ADDR = 0x801B ;
110+ static const u16 JC_CAL_USR_RIGHT_DATA_ADDR = 0x801D ;
111+ #define JC_CAL_STICK_DATA_SIZE \
112+ (JC_CAL_USR_LEFT_DATA_END - JC_CAL_USR_LEFT_DATA_ADDR + 1)
103113
114+ /* SPI storage addresses of factory calibration data */
115+ static const u16 JC_CAL_FCT_DATA_LEFT_ADDR = 0x603d ;
116+ static const u16 JC_CAL_FCT_DATA_RIGHT_ADDR = 0x6046 ;
104117
105118/* The raw analog joystick values will be mapped in terms of this magnitude */
106119static const u16 JC_MAX_STICK_MAG = 32767 ;
@@ -531,38 +544,140 @@ static int joycon_set_player_leds(struct joycon_ctlr *ctlr, u8 flash, u8 on)
531544 return joycon_send_subcmd (ctlr , req , 1 , HZ /4 );
532545}
533546
534- static const u16 DFLT_STICK_CAL_CEN = 2000 ;
535- static const u16 DFLT_STICK_CAL_MAX = 3500 ;
536- static const u16 DFLT_STICK_CAL_MIN = 500 ;
537- static int joycon_request_calibration (struct joycon_ctlr * ctlr )
547+ static int joycon_request_spi_flash_read (struct joycon_ctlr * ctlr ,
548+ u32 start_addr , u8 size , u8 * * reply )
538549{
539550 struct joycon_subcmd_request * req ;
540- u8 buffer [sizeof (* req ) + 5 ] = { 0 };
541551 struct joycon_input_report * report ;
542- struct joycon_stick_cal * cal_x ;
543- struct joycon_stick_cal * cal_y ;
552+ u8 buffer [sizeof (* req ) + 5 ] = { 0 };
553+ u8 * data ;
554+ int ret ;
555+
556+ if (!reply )
557+ return - EINVAL ;
558+
559+ req = (struct joycon_subcmd_request * )buffer ;
560+ req -> subcmd_id = JC_SUBCMD_SPI_FLASH_READ ;
561+ data = req -> data ;
562+ put_unaligned_le32 (start_addr , data );
563+ data [4 ] = size ;
564+
565+ hid_dbg (ctlr -> hdev , "requesting SPI flash data\n" );
566+ ret = joycon_send_subcmd (ctlr , req , 5 , HZ );
567+ if (ret ) {
568+ hid_err (ctlr -> hdev , "failed reading SPI flash; ret=%d\n" , ret );
569+ } else {
570+ report = (struct joycon_input_report * )ctlr -> input_buf ;
571+ /* The read data starts at the 6th byte */
572+ * reply = & report -> reply .data [5 ];
573+ }
574+ return ret ;
575+ }
576+
577+ /*
578+ * User calibration's presence is denoted with a magic byte preceding it.
579+ * returns 0 if magic val is present, 1 if not present, < 0 on error
580+ */
581+ static int joycon_check_for_cal_magic (struct joycon_ctlr * ctlr , u32 flash_addr )
582+ {
583+ int ret ;
584+ u8 * reply ;
585+
586+ ret = joycon_request_spi_flash_read (ctlr , flash_addr ,
587+ JC_CAL_USR_MAGIC_SIZE , & reply );
588+ if (ret )
589+ return ret ;
590+
591+ return reply [0 ] != JC_CAL_USR_MAGIC_0 || reply [1 ] != JC_CAL_USR_MAGIC_1 ;
592+ }
593+
594+ static int joycon_read_stick_calibration (struct joycon_ctlr * ctlr , u16 cal_addr ,
595+ struct joycon_stick_cal * cal_x ,
596+ struct joycon_stick_cal * cal_y ,
597+ bool left_stick )
598+ {
544599 s32 x_max_above ;
545600 s32 x_min_below ;
546601 s32 y_max_above ;
547602 s32 y_min_below ;
548- u8 * data ;
549603 u8 * raw_cal ;
550604 int ret ;
551605
552- req = (struct joycon_subcmd_request * )buffer ;
553- req -> subcmd_id = JC_SUBCMD_SPI_FLASH_READ ;
554- data = req -> data ;
555- data [0 ] = 0xFF & JC_CAL_DATA_START ;
556- data [1 ] = 0xFF & (JC_CAL_DATA_START >> 8 );
557- data [2 ] = 0xFF & (JC_CAL_DATA_START >> 16 );
558- data [3 ] = 0xFF & (JC_CAL_DATA_START >> 24 );
559- data [4 ] = JC_CAL_DATA_SIZE ;
606+ ret = joycon_request_spi_flash_read (ctlr , cal_addr ,
607+ JC_CAL_STICK_DATA_SIZE , & raw_cal );
608+ if (ret )
609+ return ret ;
610+
611+ /* stick calibration parsing: note the order differs based on stick */
612+ if (left_stick ) {
613+ x_max_above = hid_field_extract (ctlr -> hdev , (raw_cal + 0 ), 0 ,
614+ 12 );
615+ y_max_above = hid_field_extract (ctlr -> hdev , (raw_cal + 1 ), 4 ,
616+ 12 );
617+ cal_x -> center = hid_field_extract (ctlr -> hdev , (raw_cal + 3 ), 0 ,
618+ 12 );
619+ cal_y -> center = hid_field_extract (ctlr -> hdev , (raw_cal + 4 ), 4 ,
620+ 12 );
621+ x_min_below = hid_field_extract (ctlr -> hdev , (raw_cal + 6 ), 0 ,
622+ 12 );
623+ y_min_below = hid_field_extract (ctlr -> hdev , (raw_cal + 7 ), 4 ,
624+ 12 );
625+ } else {
626+ cal_x -> center = hid_field_extract (ctlr -> hdev , (raw_cal + 0 ), 0 ,
627+ 12 );
628+ cal_y -> center = hid_field_extract (ctlr -> hdev , (raw_cal + 1 ), 4 ,
629+ 12 );
630+ x_min_below = hid_field_extract (ctlr -> hdev , (raw_cal + 3 ), 0 ,
631+ 12 );
632+ y_min_below = hid_field_extract (ctlr -> hdev , (raw_cal + 4 ), 4 ,
633+ 12 );
634+ x_max_above = hid_field_extract (ctlr -> hdev , (raw_cal + 6 ), 0 ,
635+ 12 );
636+ y_max_above = hid_field_extract (ctlr -> hdev , (raw_cal + 7 ), 4 ,
637+ 12 );
638+ }
639+
640+ cal_x -> max = cal_x -> center + x_max_above ;
641+ cal_x -> min = cal_x -> center - x_min_below ;
642+ cal_y -> max = cal_y -> center + y_max_above ;
643+ cal_y -> min = cal_y -> center - y_min_below ;
644+
645+ return 0 ;
646+ }
647+
648+ static const u16 DFLT_STICK_CAL_CEN = 2000 ;
649+ static const u16 DFLT_STICK_CAL_MAX = 3500 ;
650+ static const u16 DFLT_STICK_CAL_MIN = 500 ;
651+ static int joycon_request_calibration (struct joycon_ctlr * ctlr )
652+ {
653+ u16 left_stick_addr = JC_CAL_FCT_DATA_LEFT_ADDR ;
654+ u16 right_stick_addr = JC_CAL_FCT_DATA_RIGHT_ADDR ;
655+ int ret ;
560656
561657 hid_dbg (ctlr -> hdev , "requesting cal data\n" );
562- ret = joycon_send_subcmd (ctlr , req , 5 , HZ );
658+
659+ /* check if user stick calibrations are present */
660+ if (!joycon_check_for_cal_magic (ctlr , JC_CAL_USR_LEFT_MAGIC_ADDR )) {
661+ left_stick_addr = JC_CAL_USR_LEFT_DATA_ADDR ;
662+ hid_info (ctlr -> hdev , "using user cal for left stick\n" );
663+ } else {
664+ hid_info (ctlr -> hdev , "using factory cal for left stick\n" );
665+ }
666+ if (!joycon_check_for_cal_magic (ctlr , JC_CAL_USR_RIGHT_MAGIC_ADDR )) {
667+ right_stick_addr = JC_CAL_USR_RIGHT_DATA_ADDR ;
668+ hid_info (ctlr -> hdev , "using user cal for right stick\n" );
669+ } else {
670+ hid_info (ctlr -> hdev , "using factory cal for right stick\n" );
671+ }
672+
673+ /* read the left stick calibration data */
674+ ret = joycon_read_stick_calibration (ctlr , left_stick_addr ,
675+ & ctlr -> left_stick_cal_x ,
676+ & ctlr -> left_stick_cal_y ,
677+ true);
563678 if (ret ) {
564679 hid_warn (ctlr -> hdev ,
565- "Failed to read stick cal, using defaults; ret =%d\n" ,
680+ "Failed to read left stick cal, using dflts; e =%d\n" ,
566681 ret );
567682
568683 ctlr -> left_stick_cal_x .center = DFLT_STICK_CAL_CEN ;
@@ -572,6 +687,17 @@ static int joycon_request_calibration(struct joycon_ctlr *ctlr)
572687 ctlr -> left_stick_cal_y .center = DFLT_STICK_CAL_CEN ;
573688 ctlr -> left_stick_cal_y .max = DFLT_STICK_CAL_MAX ;
574689 ctlr -> left_stick_cal_y .min = DFLT_STICK_CAL_MIN ;
690+ }
691+
692+ /* read the right stick calibration data */
693+ ret = joycon_read_stick_calibration (ctlr , right_stick_addr ,
694+ & ctlr -> right_stick_cal_x ,
695+ & ctlr -> right_stick_cal_y ,
696+ false);
697+ if (ret ) {
698+ hid_warn (ctlr -> hdev ,
699+ "Failed to read right stick cal, using dflts; e=%d\n" ,
700+ ret );
575701
576702 ctlr -> right_stick_cal_x .center = DFLT_STICK_CAL_CEN ;
577703 ctlr -> right_stick_cal_x .max = DFLT_STICK_CAL_MAX ;
@@ -580,44 +706,8 @@ static int joycon_request_calibration(struct joycon_ctlr *ctlr)
580706 ctlr -> right_stick_cal_y .center = DFLT_STICK_CAL_CEN ;
581707 ctlr -> right_stick_cal_y .max = DFLT_STICK_CAL_MAX ;
582708 ctlr -> right_stick_cal_y .min = DFLT_STICK_CAL_MIN ;
583-
584- return ret ;
585709 }
586710
587- report = (struct joycon_input_report * )ctlr -> input_buf ;
588- raw_cal = & report -> reply .data [5 ];
589-
590- /* left stick calibration parsing */
591- cal_x = & ctlr -> left_stick_cal_x ;
592- cal_y = & ctlr -> left_stick_cal_y ;
593-
594- x_max_above = hid_field_extract (ctlr -> hdev , (raw_cal + 0 ), 0 , 12 );
595- y_max_above = hid_field_extract (ctlr -> hdev , (raw_cal + 1 ), 4 , 12 );
596- cal_x -> center = hid_field_extract (ctlr -> hdev , (raw_cal + 3 ), 0 , 12 );
597- cal_y -> center = hid_field_extract (ctlr -> hdev , (raw_cal + 4 ), 4 , 12 );
598- x_min_below = hid_field_extract (ctlr -> hdev , (raw_cal + 6 ), 0 , 12 );
599- y_min_below = hid_field_extract (ctlr -> hdev , (raw_cal + 7 ), 4 , 12 );
600- cal_x -> max = cal_x -> center + x_max_above ;
601- cal_x -> min = cal_x -> center - x_min_below ;
602- cal_y -> max = cal_y -> center + y_max_above ;
603- cal_y -> min = cal_y -> center - y_min_below ;
604-
605- /* right stick calibration parsing */
606- raw_cal += 9 ;
607- cal_x = & ctlr -> right_stick_cal_x ;
608- cal_y = & ctlr -> right_stick_cal_y ;
609-
610- cal_x -> center = hid_field_extract (ctlr -> hdev , (raw_cal + 0 ), 0 , 12 );
611- cal_y -> center = hid_field_extract (ctlr -> hdev , (raw_cal + 1 ), 4 , 12 );
612- x_min_below = hid_field_extract (ctlr -> hdev , (raw_cal + 3 ), 0 , 12 );
613- y_min_below = hid_field_extract (ctlr -> hdev , (raw_cal + 4 ), 4 , 12 );
614- x_max_above = hid_field_extract (ctlr -> hdev , (raw_cal + 6 ), 0 , 12 );
615- y_max_above = hid_field_extract (ctlr -> hdev , (raw_cal + 7 ), 4 , 12 );
616- cal_x -> max = cal_x -> center + x_max_above ;
617- cal_x -> min = cal_x -> center - x_min_below ;
618- cal_y -> max = cal_y -> center + y_max_above ;
619- cal_y -> min = cal_y -> center - y_min_below ;
620-
621711 hid_dbg (ctlr -> hdev , "calibration:\n"
622712 "l_x_c=%d l_x_max=%d l_x_min=%d\n"
623713 "l_y_c=%d l_y_max=%d l_y_min=%d\n"
0 commit comments