Skip to content

Commit 0d6b550

Browse files
hsdenxJiri Kosina
authored andcommitted
HID: mcp2221: set gpio pin mode
in case we have GPIOLIB enabled the gpio pins are used from the current driver as gpio pins. But may the gpio functions of this pins are not enabled in the flash of the chip and so gpio access fails. In case CONFIG_IIO is not enabled we can prevent this issue of the driver simply by enabling the gpio mode for all pins. Signed-off-by: Heiko Schocher <[email protected]> Signed-off-by: Jiri Kosina <[email protected]>
1 parent 2043ae9 commit 0d6b550

File tree

1 file changed

+97
-0
lines changed

1 file changed

+97
-0
lines changed

drivers/hid/hid-mcp2221.c

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,27 @@ enum {
5555
MCP2221_ALT_F_NOT_GPIOD = 0xEF,
5656
};
5757

58+
/* MCP SRAM read offsets cmd: MCP2221_GET_SRAM_SETTINGS */
59+
enum {
60+
MCP2221_SRAM_RD_GP0 = 22,
61+
MCP2221_SRAM_RD_GP1 = 23,
62+
MCP2221_SRAM_RD_GP2 = 24,
63+
MCP2221_SRAM_RD_GP3 = 25,
64+
};
65+
66+
/* MCP SRAM write offsets cmd: MCP2221_SET_SRAM_SETTINGS */
67+
enum {
68+
MCP2221_SRAM_WR_GP_ENA_ALTER = 7,
69+
MCP2221_SRAM_WR_GP0 = 8,
70+
MCP2221_SRAM_WR_GP1 = 9,
71+
MCP2221_SRAM_WR_GP2 = 10,
72+
MCP2221_SRAM_WR_GP3 = 11,
73+
};
74+
75+
#define MCP2221_SRAM_GP_DESIGN_MASK 0x07
76+
#define MCP2221_SRAM_GP_DIRECTION_MASK 0x08
77+
#define MCP2221_SRAM_GP_VALUE_MASK 0x10
78+
5879
/* MCP GPIO direction encoding */
5980
enum {
6081
MCP2221_DIR_OUT = 0x00,
@@ -607,6 +628,80 @@ static const struct i2c_algorithm mcp_i2c_algo = {
607628
};
608629

609630
#if IS_REACHABLE(CONFIG_GPIOLIB)
631+
static int mcp_gpio_read_sram(struct mcp2221 *mcp)
632+
{
633+
int ret;
634+
635+
memset(mcp->txbuf, 0, 64);
636+
mcp->txbuf[0] = MCP2221_GET_SRAM_SETTINGS;
637+
638+
mutex_lock(&mcp->lock);
639+
ret = mcp_send_data_req_status(mcp, mcp->txbuf, 64);
640+
mutex_unlock(&mcp->lock);
641+
642+
return ret;
643+
}
644+
645+
/*
646+
* If CONFIG_IIO is not enabled, check for the gpio pins
647+
* if they are in gpio mode. For the ones which are not
648+
* in gpio mode, set them into gpio mode.
649+
*/
650+
static int mcp2221_check_gpio_pinfunc(struct mcp2221 *mcp)
651+
{
652+
int i;
653+
int needgpiofix = 0;
654+
int ret;
655+
656+
if (IS_ENABLED(CONFIG_IIO))
657+
return 0;
658+
659+
ret = mcp_gpio_read_sram(mcp);
660+
if (ret)
661+
return ret;
662+
663+
for (i = 0; i < MCP_NGPIO; i++) {
664+
if ((mcp->mode[i] & MCP2221_SRAM_GP_DESIGN_MASK) != 0x0) {
665+
dev_warn(&mcp->hdev->dev,
666+
"GPIO %d not in gpio mode\n", i);
667+
needgpiofix = 1;
668+
}
669+
}
670+
671+
if (!needgpiofix)
672+
return 0;
673+
674+
/*
675+
* Set all bytes to 0, so Bit 7 is not set. The chip
676+
* only changes content of a register when bit 7 is set.
677+
*/
678+
memset(mcp->txbuf, 0, 64);
679+
mcp->txbuf[0] = MCP2221_SET_SRAM_SETTINGS;
680+
681+
/*
682+
* Set bit 7 in MCP2221_SRAM_WR_GP_ENA_ALTER to enable
683+
* loading of a new set of gpio settings to GP SRAM
684+
*/
685+
mcp->txbuf[MCP2221_SRAM_WR_GP_ENA_ALTER] = 0x80;
686+
for (i = 0; i < MCP_NGPIO; i++) {
687+
if ((mcp->mode[i] & MCP2221_SRAM_GP_DESIGN_MASK) == 0x0) {
688+
/* write current GPIO mode */
689+
mcp->txbuf[MCP2221_SRAM_WR_GP0 + i] = mcp->mode[i];
690+
} else {
691+
/* pin is not in gpio mode, set it to input mode */
692+
mcp->txbuf[MCP2221_SRAM_WR_GP0 + i] = 0x08;
693+
dev_warn(&mcp->hdev->dev,
694+
"Set GPIO mode for gpio pin %d!\n", i);
695+
}
696+
}
697+
698+
mutex_lock(&mcp->lock);
699+
ret = mcp_send_data_req_status(mcp, mcp->txbuf, 64);
700+
mutex_unlock(&mcp->lock);
701+
702+
return ret;
703+
}
704+
610705
static int mcp_gpio_get(struct gpio_chip *gc,
611706
unsigned int offset)
612707
{
@@ -1218,6 +1313,8 @@ static int mcp2221_probe(struct hid_device *hdev,
12181313
ret = devm_gpiochip_add_data(&hdev->dev, mcp->gc, mcp);
12191314
if (ret)
12201315
return ret;
1316+
1317+
mcp2221_check_gpio_pinfunc(mcp);
12211318
#endif
12221319

12231320
#if IS_REACHABLE(CONFIG_IIO)

0 commit comments

Comments
 (0)