Skip to content

Commit c8acfe0

Browse files
Karoly Padosjhovold
authored andcommitted
USB: serial: cp210x: implement GPIO support for CP2102N
This patch adds GPIO support for CP2102N devices. It introduces new generic code to support emulating separate input and outputs directions even though these devices only know output modes (open-drain and pushpull). Existing GPIO support for CP2105 has been migrated over to the new code structure. Only limitation is that for the QFN28 variant, only 4 out of 7 GPIOs are supported. This is because the config array locations of the last 3 pins are not documented, and reverse engineering revealed offsets that conflicted with other documented functions. Hence we'll play it safe instead until somebody clears this up further. Signed-off-by: Karoly Pados <pados@pados.hu> [ johan: fix style issues and a couple of minor bugs; use Karoly's updated commit message ] Acked-by: Martyn Welch <martyn.welch@collabora.co.uk> Signed-off-by: Johan Hovold <johan@kernel.org>
1 parent 5edb65a commit c8acfe0

File tree

1 file changed

+209
-36
lines changed

1 file changed

+209
-36
lines changed

drivers/usb/serial/cp210x.c

Lines changed: 209 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -224,9 +224,10 @@ MODULE_DEVICE_TABLE(usb, id_table);
224224
struct cp210x_serial_private {
225225
#ifdef CONFIG_GPIOLIB
226226
struct gpio_chip gc;
227-
u8 config;
228-
u8 gpio_mode;
229227
bool gpio_registered;
228+
u8 gpio_pushpull;
229+
u8 gpio_altfunc;
230+
u8 gpio_input;
230231
#endif
231232
u8 partnum;
232233
speed_t max_speed;
@@ -343,6 +344,7 @@ static struct usb_serial_driver * const serial_drivers[] = {
343344
#define CONTROL_WRITE_RTS 0x0200
344345

345346
/* CP210X_VENDOR_SPECIFIC values */
347+
#define CP210X_READ_2NCONFIG 0x000E
346348
#define CP210X_READ_LATCH 0x00C2
347349
#define CP210X_GET_PARTNUM 0x370B
348350
#define CP210X_GET_PORTCONFIG 0x370C
@@ -452,6 +454,12 @@ struct cp210x_config {
452454
#define CP2105_GPIO1_RXLED_MODE BIT(1)
453455
#define CP2105_GPIO1_RS485_MODE BIT(2)
454456

457+
/* CP2102N configuration array indices */
458+
#define CP210X_2NCONFIG_CONFIG_VERSION_IDX 2
459+
#define CP210X_2NCONFIG_GPIO_MODE_IDX 581
460+
#define CP210X_2NCONFIG_GPIO_RSTLATCH_IDX 587
461+
#define CP210X_2NCONFIG_GPIO_CONTROL_IDX 600
462+
455463
/* CP210X_VENDOR_SPECIFIC, CP210X_WRITE_LATCH call writes these 0x2 bytes. */
456464
struct cp210x_gpio_write {
457465
u8 mask;
@@ -1313,28 +1321,24 @@ static int cp210x_gpio_request(struct gpio_chip *gc, unsigned int offset)
13131321
struct usb_serial *serial = gpiochip_get_data(gc);
13141322
struct cp210x_serial_private *priv = usb_get_serial_data(serial);
13151323

1316-
switch (offset) {
1317-
case 0:
1318-
if (priv->config & CP2105_GPIO0_TXLED_MODE)
1319-
return -ENODEV;
1320-
break;
1321-
case 1:
1322-
if (priv->config & (CP2105_GPIO1_RXLED_MODE |
1323-
CP2105_GPIO1_RS485_MODE))
1324-
return -ENODEV;
1325-
break;
1326-
}
1324+
if (priv->gpio_altfunc & BIT(offset))
1325+
return -ENODEV;
13271326

13281327
return 0;
13291328
}
13301329

13311330
static int cp210x_gpio_get(struct gpio_chip *gc, unsigned int gpio)
13321331
{
13331332
struct usb_serial *serial = gpiochip_get_data(gc);
1333+
struct cp210x_serial_private *priv = usb_get_serial_data(serial);
1334+
u8 req_type = REQTYPE_DEVICE_TO_HOST;
13341335
int result;
13351336
u8 buf;
13361337

1337-
result = cp210x_read_vendor_block(serial, REQTYPE_INTERFACE_TO_HOST,
1338+
if (priv->partnum == CP210X_PARTNUM_CP2105)
1339+
req_type = REQTYPE_INTERFACE_TO_HOST;
1340+
1341+
result = cp210x_read_vendor_block(serial, req_type,
13381342
CP210X_READ_LATCH, &buf, sizeof(buf));
13391343
if (result < 0)
13401344
return result;
@@ -1345,7 +1349,9 @@ static int cp210x_gpio_get(struct gpio_chip *gc, unsigned int gpio)
13451349
static void cp210x_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value)
13461350
{
13471351
struct usb_serial *serial = gpiochip_get_data(gc);
1352+
struct cp210x_serial_private *priv = usb_get_serial_data(serial);
13481353
struct cp210x_gpio_write buf;
1354+
int result;
13491355

13501356
if (value == 1)
13511357
buf.state = BIT(gpio);
@@ -1354,25 +1360,68 @@ static void cp210x_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value)
13541360

13551361
buf.mask = BIT(gpio);
13561362

1357-
cp210x_write_vendor_block(serial, REQTYPE_HOST_TO_INTERFACE,
1358-
CP210X_WRITE_LATCH, &buf, sizeof(buf));
1363+
if (priv->partnum == CP210X_PARTNUM_CP2105) {
1364+
result = cp210x_write_vendor_block(serial,
1365+
REQTYPE_HOST_TO_INTERFACE,
1366+
CP210X_WRITE_LATCH, &buf,
1367+
sizeof(buf));
1368+
} else {
1369+
u16 wIndex = buf.state << 8 | buf.mask;
1370+
1371+
result = usb_control_msg(serial->dev,
1372+
usb_sndctrlpipe(serial->dev, 0),
1373+
CP210X_VENDOR_SPECIFIC,
1374+
REQTYPE_HOST_TO_DEVICE,
1375+
CP210X_WRITE_LATCH,
1376+
wIndex,
1377+
NULL, 0, USB_CTRL_SET_TIMEOUT);
1378+
}
1379+
1380+
if (result < 0) {
1381+
dev_err(&serial->interface->dev, "failed to set GPIO value: %d\n",
1382+
result);
1383+
}
13591384
}
13601385

13611386
static int cp210x_gpio_direction_get(struct gpio_chip *gc, unsigned int gpio)
13621387
{
1363-
/* Hardware does not support an input mode */
1364-
return 0;
1388+
struct usb_serial *serial = gpiochip_get_data(gc);
1389+
struct cp210x_serial_private *priv = usb_get_serial_data(serial);
1390+
1391+
return priv->gpio_input & BIT(gpio);
13651392
}
13661393

13671394
static int cp210x_gpio_direction_input(struct gpio_chip *gc, unsigned int gpio)
13681395
{
1369-
/* Hardware does not support an input mode */
1370-
return -ENOTSUPP;
1396+
struct usb_serial *serial = gpiochip_get_data(gc);
1397+
struct cp210x_serial_private *priv = usb_get_serial_data(serial);
1398+
1399+
if (priv->partnum == CP210X_PARTNUM_CP2105) {
1400+
/* hardware does not support an input mode */
1401+
return -ENOTSUPP;
1402+
}
1403+
1404+
/* push-pull pins cannot be changed to be inputs */
1405+
if (priv->gpio_pushpull & BIT(gpio))
1406+
return -EINVAL;
1407+
1408+
/* make sure to release pin if it is being driven low */
1409+
cp210x_gpio_set(gc, gpio, 1);
1410+
1411+
priv->gpio_input |= BIT(gpio);
1412+
1413+
return 0;
13711414
}
13721415

13731416
static int cp210x_gpio_direction_output(struct gpio_chip *gc, unsigned int gpio,
13741417
int value)
13751418
{
1419+
struct usb_serial *serial = gpiochip_get_data(gc);
1420+
struct cp210x_serial_private *priv = usb_get_serial_data(serial);
1421+
1422+
priv->gpio_input &= ~BIT(gpio);
1423+
cp210x_gpio_set(gc, gpio, value);
1424+
13761425
return 0;
13771426
}
13781427

@@ -1385,11 +1434,11 @@ static int cp210x_gpio_set_config(struct gpio_chip *gc, unsigned int gpio,
13851434

13861435
/* Succeed only if in correct mode (this can't be set at runtime) */
13871436
if ((param == PIN_CONFIG_DRIVE_PUSH_PULL) &&
1388-
(priv->gpio_mode & BIT(gpio)))
1437+
(priv->gpio_pushpull & BIT(gpio)))
13891438
return 0;
13901439

13911440
if ((param == PIN_CONFIG_DRIVE_OPEN_DRAIN) &&
1392-
!(priv->gpio_mode & BIT(gpio)))
1441+
!(priv->gpio_pushpull & BIT(gpio)))
13931442
return 0;
13941443

13951444
return -ENOTSUPP;
@@ -1402,12 +1451,13 @@ static int cp210x_gpio_set_config(struct gpio_chip *gc, unsigned int gpio,
14021451
* this driver that provide GPIO do so in a way that does not impact other
14031452
* signals and are thus expected to have very different initialisation.
14041453
*/
1405-
static int cp2105_shared_gpio_init(struct usb_serial *serial)
1454+
static int cp2105_gpioconf_init(struct usb_serial *serial)
14061455
{
14071456
struct cp210x_serial_private *priv = usb_get_serial_data(serial);
14081457
struct cp210x_pin_mode mode;
14091458
struct cp210x_config config;
14101459
u8 intf_num = cp210x_interface_num(serial);
1460+
u8 iface_config;
14111461
int result;
14121462

14131463
result = cp210x_read_vendor_block(serial, REQTYPE_DEVICE_TO_HOST,
@@ -1424,27 +1474,152 @@ static int cp2105_shared_gpio_init(struct usb_serial *serial)
14241474

14251475
/* 2 banks of GPIO - One for the pins taken from each serial port */
14261476
if (intf_num == 0) {
1427-
if (mode.eci == CP210X_PIN_MODE_MODEM)
1477+
if (mode.eci == CP210X_PIN_MODE_MODEM) {
1478+
/* mark all GPIOs of this interface as reserved */
1479+
priv->gpio_altfunc = 0xff;
14281480
return 0;
1481+
}
14291482

1430-
priv->config = config.eci_cfg;
1431-
priv->gpio_mode = (u8)((le16_to_cpu(config.gpio_mode) &
1483+
iface_config = config.eci_cfg;
1484+
priv->gpio_pushpull = (u8)((le16_to_cpu(config.gpio_mode) &
14321485
CP210X_ECI_GPIO_MODE_MASK) >>
14331486
CP210X_ECI_GPIO_MODE_OFFSET);
14341487
priv->gc.ngpio = 2;
14351488
} else if (intf_num == 1) {
1436-
if (mode.sci == CP210X_PIN_MODE_MODEM)
1489+
if (mode.sci == CP210X_PIN_MODE_MODEM) {
1490+
/* mark all GPIOs of this interface as reserved */
1491+
priv->gpio_altfunc = 0xff;
14371492
return 0;
1493+
}
14381494

1439-
priv->config = config.sci_cfg;
1440-
priv->gpio_mode = (u8)((le16_to_cpu(config.gpio_mode) &
1495+
iface_config = config.sci_cfg;
1496+
priv->gpio_pushpull = (u8)((le16_to_cpu(config.gpio_mode) &
14411497
CP210X_SCI_GPIO_MODE_MASK) >>
14421498
CP210X_SCI_GPIO_MODE_OFFSET);
14431499
priv->gc.ngpio = 3;
14441500
} else {
14451501
return -ENODEV;
14461502
}
14471503

1504+
/* mark all pins which are not in GPIO mode */
1505+
if (iface_config & CP2105_GPIO0_TXLED_MODE) /* GPIO 0 */
1506+
priv->gpio_altfunc |= BIT(0);
1507+
if (iface_config & (CP2105_GPIO1_RXLED_MODE | /* GPIO 1 */
1508+
CP2105_GPIO1_RS485_MODE))
1509+
priv->gpio_altfunc |= BIT(1);
1510+
1511+
/* driver implementation for CP2105 only supports outputs */
1512+
priv->gpio_input = 0;
1513+
1514+
return 0;
1515+
}
1516+
1517+
static int cp2102n_gpioconf_init(struct usb_serial *serial)
1518+
{
1519+
struct cp210x_serial_private *priv = usb_get_serial_data(serial);
1520+
const u16 config_size = 0x02a6;
1521+
u8 gpio_rst_latch;
1522+
u8 config_version;
1523+
u8 gpio_pushpull;
1524+
u8 *config_buf;
1525+
u8 gpio_latch;
1526+
u8 gpio_ctrl;
1527+
int result;
1528+
u8 i;
1529+
1530+
/*
1531+
* Retrieve device configuration from the device.
1532+
* The array received contains all customization settings done at the
1533+
* factory/manufacturer. Format of the array is documented at the
1534+
* time of writing at:
1535+
* https://www.silabs.com/community/interface/knowledge-base.entry.html/2017/03/31/cp2102n_setconfig-xsfa
1536+
*/
1537+
config_buf = kmalloc(config_size, GFP_KERNEL);
1538+
if (!config_buf)
1539+
return -ENOMEM;
1540+
1541+
result = cp210x_read_vendor_block(serial,
1542+
REQTYPE_DEVICE_TO_HOST,
1543+
CP210X_READ_2NCONFIG,
1544+
config_buf,
1545+
config_size);
1546+
if (result < 0) {
1547+
kfree(config_buf);
1548+
return result;
1549+
}
1550+
1551+
config_version = config_buf[CP210X_2NCONFIG_CONFIG_VERSION_IDX];
1552+
gpio_pushpull = config_buf[CP210X_2NCONFIG_GPIO_MODE_IDX];
1553+
gpio_ctrl = config_buf[CP210X_2NCONFIG_GPIO_CONTROL_IDX];
1554+
gpio_rst_latch = config_buf[CP210X_2NCONFIG_GPIO_RSTLATCH_IDX];
1555+
1556+
kfree(config_buf);
1557+
1558+
/* Make sure this is a config format we understand. */
1559+
if (config_version != 0x01)
1560+
return -ENOTSUPP;
1561+
1562+
/*
1563+
* We only support 4 GPIOs even on the QFN28 package, because
1564+
* config locations of GPIOs 4-6 determined using reverse
1565+
* engineering revealed conflicting offsets with other
1566+
* documented functions. So we'll just play it safe for now.
1567+
*/
1568+
priv->gc.ngpio = 4;
1569+
1570+
/*
1571+
* Get default pin states after reset. Needed so we can determine
1572+
* the direction of an open-drain pin.
1573+
*/
1574+
gpio_latch = (gpio_rst_latch >> 3) & 0x0f;
1575+
1576+
/* 0 indicates open-drain mode, 1 is push-pull */
1577+
priv->gpio_pushpull = (gpio_pushpull >> 3) & 0x0f;
1578+
1579+
/* 0 indicates GPIO mode, 1 is alternate function */
1580+
priv->gpio_altfunc = (gpio_ctrl >> 2) & 0x0f;
1581+
1582+
/*
1583+
* The CP2102N does not strictly has input and output pin modes,
1584+
* it only knows open-drain and push-pull modes which is set at
1585+
* factory. An open-drain pin can function both as an
1586+
* input or an output. We emulate input mode for open-drain pins
1587+
* by making sure they are not driven low, and we do not allow
1588+
* push-pull pins to be set as an input.
1589+
*/
1590+
for (i = 0; i < priv->gc.ngpio; ++i) {
1591+
/*
1592+
* Set direction to "input" iff pin is open-drain and reset
1593+
* value is 1.
1594+
*/
1595+
if (!(priv->gpio_pushpull & BIT(i)) && (gpio_latch & BIT(i)))
1596+
priv->gpio_input |= BIT(i);
1597+
}
1598+
1599+
return 0;
1600+
}
1601+
1602+
static int cp210x_gpio_init(struct usb_serial *serial)
1603+
{
1604+
struct cp210x_serial_private *priv = usb_get_serial_data(serial);
1605+
int result;
1606+
1607+
switch (priv->partnum) {
1608+
case CP210X_PARTNUM_CP2105:
1609+
result = cp2105_gpioconf_init(serial);
1610+
break;
1611+
case CP210X_PARTNUM_CP2102N_QFN28:
1612+
case CP210X_PARTNUM_CP2102N_QFN24:
1613+
case CP210X_PARTNUM_CP2102N_QFN20:
1614+
result = cp2102n_gpioconf_init(serial);
1615+
break;
1616+
default:
1617+
return 0;
1618+
}
1619+
1620+
if (result < 0)
1621+
return result;
1622+
14481623
priv->gc.label = "cp210x";
14491624
priv->gc.request = cp210x_gpio_request;
14501625
priv->gc.get_direction = cp210x_gpio_direction_get;
@@ -1477,7 +1652,7 @@ static void cp210x_gpio_remove(struct usb_serial *serial)
14771652

14781653
#else
14791654

1480-
static int cp2105_shared_gpio_init(struct usb_serial *serial)
1655+
static int cp210x_gpio_init(struct usb_serial *serial)
14811656
{
14821657
return 0;
14831658
}
@@ -1588,12 +1763,10 @@ static int cp210x_attach(struct usb_serial *serial)
15881763

15891764
cp210x_init_max_speed(serial);
15901765

1591-
if (priv->partnum == CP210X_PARTNUM_CP2105) {
1592-
result = cp2105_shared_gpio_init(serial);
1593-
if (result < 0) {
1594-
dev_err(&serial->interface->dev,
1595-
"GPIO initialisation failed, continuing without GPIO support\n");
1596-
}
1766+
result = cp210x_gpio_init(serial);
1767+
if (result < 0) {
1768+
dev_err(&serial->interface->dev, "GPIO initialisation failed: %d\n",
1769+
result);
15971770
}
15981771

15991772
return 0;

0 commit comments

Comments
 (0)