15
15
#include <linux/hid.h>
16
16
#include <linux/hidraw.h>
17
17
#include <linux/i2c.h>
18
+ #include <linux/gpio/driver.h>
18
19
#include "hid-ids.h"
19
20
20
21
/* Commands codes in a raw output report */
27
28
MCP2221_I2C_PARAM_OR_STATUS = 0x10 ,
28
29
MCP2221_I2C_SET_SPEED = 0x20 ,
29
30
MCP2221_I2C_CANCEL = 0x10 ,
31
+ MCP2221_GPIO_SET = 0x50 ,
32
+ MCP2221_GPIO_GET = 0x51 ,
30
33
};
31
34
32
35
/* Response codes in a raw input report */
42
45
MCP2221_I2C_WRADDRL_SEND = 0x21 ,
43
46
MCP2221_I2C_ADDR_NACK = 0x25 ,
44
47
MCP2221_I2C_READ_COMPL = 0x55 ,
48
+ MCP2221_ALT_F_NOT_GPIOV = 0xEE ,
49
+ MCP2221_ALT_F_NOT_GPIOD = 0xEF ,
45
50
};
46
51
47
52
/*
@@ -59,6 +64,9 @@ struct mcp2221 {
59
64
int rxbuf_idx ;
60
65
int status ;
61
66
u8 cur_i2c_clk_div ;
67
+ struct gpio_chip * gc ;
68
+ u8 gp_idx ;
69
+ u8 gpio_dir ;
62
70
};
63
71
64
72
/*
@@ -526,6 +534,110 @@ static const struct i2c_algorithm mcp_i2c_algo = {
526
534
.functionality = mcp_i2c_func ,
527
535
};
528
536
537
+ static int mcp_gpio_get (struct gpio_chip * gc ,
538
+ unsigned int offset )
539
+ {
540
+ int ret ;
541
+ struct mcp2221 * mcp = gpiochip_get_data (gc );
542
+
543
+ mcp -> txbuf [0 ] = MCP2221_GPIO_GET ;
544
+
545
+ mcp -> gp_idx = (offset + 1 ) * 2 ;
546
+
547
+ mutex_lock (& mcp -> lock );
548
+ ret = mcp_send_data_req_status (mcp , mcp -> txbuf , 1 );
549
+ mutex_unlock (& mcp -> lock );
550
+
551
+ return ret ;
552
+ }
553
+
554
+ static void mcp_gpio_set (struct gpio_chip * gc ,
555
+ unsigned int offset , int value )
556
+ {
557
+ struct mcp2221 * mcp = gpiochip_get_data (gc );
558
+
559
+ memset (mcp -> txbuf , 0 , 18 );
560
+ mcp -> txbuf [0 ] = MCP2221_GPIO_SET ;
561
+
562
+ mcp -> gp_idx = ((offset + 1 ) * 4 ) - 1 ;
563
+
564
+ mcp -> txbuf [mcp -> gp_idx - 1 ] = 1 ;
565
+ mcp -> txbuf [mcp -> gp_idx ] = !!value ;
566
+
567
+ mutex_lock (& mcp -> lock );
568
+ mcp_send_data_req_status (mcp , mcp -> txbuf , 18 );
569
+ mutex_unlock (& mcp -> lock );
570
+ }
571
+
572
+ static int mcp_gpio_dir_set (struct mcp2221 * mcp ,
573
+ unsigned int offset , u8 val )
574
+ {
575
+ memset (mcp -> txbuf , 0 , 18 );
576
+ mcp -> txbuf [0 ] = MCP2221_GPIO_SET ;
577
+
578
+ mcp -> gp_idx = (offset + 1 ) * 5 ;
579
+
580
+ mcp -> txbuf [mcp -> gp_idx - 1 ] = 1 ;
581
+ mcp -> txbuf [mcp -> gp_idx ] = val ;
582
+
583
+ return mcp_send_data_req_status (mcp , mcp -> txbuf , 18 );
584
+ }
585
+
586
+ static int mcp_gpio_direction_input (struct gpio_chip * gc ,
587
+ unsigned int offset )
588
+ {
589
+ int ret ;
590
+ struct mcp2221 * mcp = gpiochip_get_data (gc );
591
+
592
+ mutex_lock (& mcp -> lock );
593
+ ret = mcp_gpio_dir_set (mcp , offset , 0 );
594
+ mutex_unlock (& mcp -> lock );
595
+
596
+ return ret ;
597
+ }
598
+
599
+ static int mcp_gpio_direction_output (struct gpio_chip * gc ,
600
+ unsigned int offset , int value )
601
+ {
602
+ int ret ;
603
+ struct mcp2221 * mcp = gpiochip_get_data (gc );
604
+
605
+ mutex_lock (& mcp -> lock );
606
+ ret = mcp_gpio_dir_set (mcp , offset , 1 );
607
+ mutex_unlock (& mcp -> lock );
608
+
609
+ /* Can't configure as output, bailout early */
610
+ if (ret )
611
+ return ret ;
612
+
613
+ mcp_gpio_set (gc , offset , value );
614
+
615
+ return 0 ;
616
+ }
617
+
618
+ static int mcp_gpio_get_direction (struct gpio_chip * gc ,
619
+ unsigned int offset )
620
+ {
621
+ int ret ;
622
+ struct mcp2221 * mcp = gpiochip_get_data (gc );
623
+
624
+ mcp -> txbuf [0 ] = MCP2221_GPIO_GET ;
625
+
626
+ mcp -> gp_idx = (offset + 1 ) * 2 ;
627
+
628
+ mutex_lock (& mcp -> lock );
629
+ ret = mcp_send_data_req_status (mcp , mcp -> txbuf , 1 );
630
+ mutex_unlock (& mcp -> lock );
631
+
632
+ if (ret )
633
+ return ret ;
634
+
635
+ if (mcp -> gpio_dir )
636
+ return GPIO_LINE_DIRECTION_IN ;
637
+
638
+ return GPIO_LINE_DIRECTION_OUT ;
639
+ }
640
+
529
641
/* Gives current state of i2c engine inside mcp2221 */
530
642
static int mcp_get_i2c_eng_state (struct mcp2221 * mcp ,
531
643
u8 * data , u8 idx )
@@ -638,6 +750,39 @@ static int mcp2221_raw_event(struct hid_device *hdev,
638
750
complete (& mcp -> wait_in_report );
639
751
break ;
640
752
753
+ case MCP2221_GPIO_GET :
754
+ switch (data [1 ]) {
755
+ case MCP2221_SUCCESS :
756
+ if ((data [mcp -> gp_idx ] == MCP2221_ALT_F_NOT_GPIOV ) ||
757
+ (data [mcp -> gp_idx + 1 ] == MCP2221_ALT_F_NOT_GPIOD )) {
758
+ mcp -> status = - ENOENT ;
759
+ } else {
760
+ mcp -> status = !!data [mcp -> gp_idx ];
761
+ mcp -> gpio_dir = !!data [mcp -> gp_idx + 1 ];
762
+ }
763
+ break ;
764
+ default :
765
+ mcp -> status = - EAGAIN ;
766
+ }
767
+ complete (& mcp -> wait_in_report );
768
+ break ;
769
+
770
+ case MCP2221_GPIO_SET :
771
+ switch (data [1 ]) {
772
+ case MCP2221_SUCCESS :
773
+ if ((data [mcp -> gp_idx ] == MCP2221_ALT_F_NOT_GPIOV ) ||
774
+ (data [mcp -> gp_idx - 1 ] == MCP2221_ALT_F_NOT_GPIOV )) {
775
+ mcp -> status = - ENOENT ;
776
+ } else {
777
+ mcp -> status = 0 ;
778
+ }
779
+ break ;
780
+ default :
781
+ mcp -> status = - EAGAIN ;
782
+ }
783
+ complete (& mcp -> wait_in_report );
784
+ break ;
785
+
641
786
default :
642
787
mcp -> status = - EIO ;
643
788
complete (& mcp -> wait_in_report );
@@ -702,8 +847,32 @@ static int mcp2221_probe(struct hid_device *hdev,
702
847
}
703
848
i2c_set_adapdata (& mcp -> adapter , mcp );
704
849
850
+ /* Setup GPIO chip */
851
+ mcp -> gc = devm_kzalloc (& hdev -> dev , sizeof (* mcp -> gc ), GFP_KERNEL );
852
+ if (!mcp -> gc ) {
853
+ ret = - ENOMEM ;
854
+ goto err_gc ;
855
+ }
856
+
857
+ mcp -> gc -> label = "mcp2221_gpio" ;
858
+ mcp -> gc -> direction_input = mcp_gpio_direction_input ;
859
+ mcp -> gc -> direction_output = mcp_gpio_direction_output ;
860
+ mcp -> gc -> get_direction = mcp_gpio_get_direction ;
861
+ mcp -> gc -> set = mcp_gpio_set ;
862
+ mcp -> gc -> get = mcp_gpio_get ;
863
+ mcp -> gc -> ngpio = 4 ;
864
+ mcp -> gc -> base = -1 ;
865
+ mcp -> gc -> can_sleep = 1 ;
866
+ mcp -> gc -> parent = & hdev -> dev ;
867
+
868
+ ret = devm_gpiochip_add_data (& hdev -> dev , mcp -> gc , mcp );
869
+ if (ret )
870
+ goto err_gc ;
871
+
705
872
return 0 ;
706
873
874
+ err_gc :
875
+ i2c_del_adapter (& mcp -> adapter );
707
876
err_i2c :
708
877
hid_hw_close (mcp -> hdev );
709
878
err_hstop :
0 commit comments