Skip to content

Commit b46d740

Browse files
author
Jiri Kosina
committed
Merge branch 'for-6.17/mcp2221' into for-linus
- fix for behavior of the hid-mcp2221 driver for !CONFIG_IIO cases (Heiko Schocher)
2 parents 41a6f0e + a5db159 commit b46d740

File tree

1 file changed

+100
-8
lines changed

1 file changed

+100
-8
lines changed

drivers/hid/hid-mcp2221.c

Lines changed: 100 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
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 */
5981
enum {
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+
610700
static 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

Comments
 (0)