1818#include <linux/i2c.h>
1919#include <linux/gpio/driver.h>
2020#include <linux/iio/iio.h>
21+ #include <linux/minmax.h>
2122#include "hid-ids.h"
2223
2324/* Commands codes in a raw output report */
@@ -55,6 +56,27 @@ enum {
5556 MCP2221_ALT_F_NOT_GPIOD = 0xEF ,
5657};
5758
59+ /* MCP SRAM read offsets cmd: MCP2221_GET_SRAM_SETTINGS */
60+ enum {
61+ MCP2221_SRAM_RD_GP0 = 22 ,
62+ MCP2221_SRAM_RD_GP1 = 23 ,
63+ MCP2221_SRAM_RD_GP2 = 24 ,
64+ MCP2221_SRAM_RD_GP3 = 25 ,
65+ };
66+
67+ /* MCP SRAM write offsets cmd: MCP2221_SET_SRAM_SETTINGS */
68+ enum {
69+ MCP2221_SRAM_WR_GP_ENA_ALTER = 7 ,
70+ MCP2221_SRAM_WR_GP0 = 8 ,
71+ MCP2221_SRAM_WR_GP1 = 9 ,
72+ MCP2221_SRAM_WR_GP2 = 10 ,
73+ MCP2221_SRAM_WR_GP3 = 11 ,
74+ };
75+
76+ #define MCP2221_SRAM_GP_DESIGN_MASK 0x07
77+ #define MCP2221_SRAM_GP_DIRECTION_MASK 0x08
78+ #define MCP2221_SRAM_GP_VALUE_MASK 0x10
79+
5880/* MCP GPIO direction encoding */
5981enum {
6082 MCP2221_DIR_OUT = 0x00 ,
@@ -241,10 +263,7 @@ static int mcp_i2c_write(struct mcp2221 *mcp,
241263
242264 idx = 0 ;
243265 sent = 0 ;
244- if (msg -> len < 60 )
245- len = msg -> len ;
246- else
247- len = 60 ;
266+ len = min (msg -> len , 60 );
248267
249268 do {
250269 mcp -> txbuf [0 ] = type ;
@@ -271,10 +290,7 @@ static int mcp_i2c_write(struct mcp2221 *mcp,
271290 break ;
272291
273292 idx = idx + len ;
274- if ((msg -> len - sent ) < 60 )
275- len = msg -> len - sent ;
276- else
277- len = 60 ;
293+ len = min (msg -> len - sent , 60 );
278294
279295 /*
280296 * Testing shows delay is needed between successive writes
@@ -607,6 +623,80 @@ static const struct i2c_algorithm mcp_i2c_algo = {
607623};
608624
609625#if IS_REACHABLE (CONFIG_GPIOLIB )
626+ static int mcp_gpio_read_sram (struct mcp2221 * mcp )
627+ {
628+ int ret ;
629+
630+ memset (mcp -> txbuf , 0 , 64 );
631+ mcp -> txbuf [0 ] = MCP2221_GET_SRAM_SETTINGS ;
632+
633+ mutex_lock (& mcp -> lock );
634+ ret = mcp_send_data_req_status (mcp , mcp -> txbuf , 64 );
635+ mutex_unlock (& mcp -> lock );
636+
637+ return ret ;
638+ }
639+
640+ /*
641+ * If CONFIG_IIO is not enabled, check for the gpio pins
642+ * if they are in gpio mode. For the ones which are not
643+ * in gpio mode, set them into gpio mode.
644+ */
645+ static int mcp2221_check_gpio_pinfunc (struct mcp2221 * mcp )
646+ {
647+ int i ;
648+ int needgpiofix = 0 ;
649+ int ret ;
650+
651+ if (IS_ENABLED (CONFIG_IIO ))
652+ return 0 ;
653+
654+ ret = mcp_gpio_read_sram (mcp );
655+ if (ret )
656+ return ret ;
657+
658+ for (i = 0 ; i < MCP_NGPIO ; i ++ ) {
659+ if ((mcp -> mode [i ] & MCP2221_SRAM_GP_DESIGN_MASK ) != 0x0 ) {
660+ dev_warn (& mcp -> hdev -> dev ,
661+ "GPIO %d not in gpio mode\n" , i );
662+ needgpiofix = 1 ;
663+ }
664+ }
665+
666+ if (!needgpiofix )
667+ return 0 ;
668+
669+ /*
670+ * Set all bytes to 0, so Bit 7 is not set. The chip
671+ * only changes content of a register when bit 7 is set.
672+ */
673+ memset (mcp -> txbuf , 0 , 64 );
674+ mcp -> txbuf [0 ] = MCP2221_SET_SRAM_SETTINGS ;
675+
676+ /*
677+ * Set bit 7 in MCP2221_SRAM_WR_GP_ENA_ALTER to enable
678+ * loading of a new set of gpio settings to GP SRAM
679+ */
680+ mcp -> txbuf [MCP2221_SRAM_WR_GP_ENA_ALTER ] = 0x80 ;
681+ for (i = 0 ; i < MCP_NGPIO ; i ++ ) {
682+ if ((mcp -> mode [i ] & MCP2221_SRAM_GP_DESIGN_MASK ) == 0x0 ) {
683+ /* write current GPIO mode */
684+ mcp -> txbuf [MCP2221_SRAM_WR_GP0 + i ] = mcp -> mode [i ];
685+ } else {
686+ /* pin is not in gpio mode, set it to input mode */
687+ mcp -> txbuf [MCP2221_SRAM_WR_GP0 + i ] = 0x08 ;
688+ dev_warn (& mcp -> hdev -> dev ,
689+ "Set GPIO mode for gpio pin %d!\n" , i );
690+ }
691+ }
692+
693+ mutex_lock (& mcp -> lock );
694+ ret = mcp_send_data_req_status (mcp , mcp -> txbuf , 64 );
695+ mutex_unlock (& mcp -> lock );
696+
697+ return ret ;
698+ }
699+
610700static int mcp_gpio_get (struct gpio_chip * gc ,
611701 unsigned int offset )
612702{
@@ -1218,6 +1308,8 @@ static int mcp2221_probe(struct hid_device *hdev,
12181308 ret = devm_gpiochip_add_data (& hdev -> dev , mcp -> gc , mcp );
12191309 if (ret )
12201310 return ret ;
1311+
1312+ mcp2221_check_gpio_pinfunc (mcp );
12211313#endif
12221314
12231315#if IS_REACHABLE (CONFIG_IIO )
0 commit comments