Hi, Almost looks good to me. I added some comments.
On 10/9/20 7:39 AM, Michael Auchter wrote: > This patch adds an extcon driver for the TI TUSB320 USB Type-C device. > This can be used to detect whether the port is configured as a > downstream or upstream facing port. > > Signed-off-by: Michael Auchter <michael.auch...@ni.com> > --- > drivers/extcon/Kconfig | 7 ++ > drivers/extcon/Makefile | 1 + > drivers/extcon/extcon-usbc-tusb320.c | 180 +++++++++++++++++++++++++++ > 3 files changed, 188 insertions(+) > create mode 100644 drivers/extcon/extcon-usbc-tusb320.c > > diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig > index aac507bff135..241acaf8b882 100644 > --- a/drivers/extcon/Kconfig > +++ b/drivers/extcon/Kconfig > @@ -186,4 +186,11 @@ config EXTCON_USBC_CROS_EC > Say Y here to enable USB Type C cable detection extcon support when > using Chrome OS EC based USB Type-C ports. > > +config EXTCON_USBC_TUSB320 > + tristate "TI TUSB320 USB-C extcon support" > + depends on GPIOLIB || COMPILE_TEST > + help > + Say Y here to enable support for USB Type C cable detection extcon > + support using a TUSB320. > + > endif > diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile > index 52096fd8a216..fe10a1b7d18b 100644 > --- a/drivers/extcon/Makefile > +++ b/drivers/extcon/Makefile > @@ -25,3 +25,4 @@ obj-$(CONFIG_EXTCON_RT8973A) += extcon-rt8973a.o > obj-$(CONFIG_EXTCON_SM5502) += extcon-sm5502.o > obj-$(CONFIG_EXTCON_USB_GPIO) += extcon-usb-gpio.o > obj-$(CONFIG_EXTCON_USBC_CROS_EC) += extcon-usbc-cros-ec.o > +obj-$(CONFIG_EXTCON_USBC_TUSB320) += extcon-usbc-tusb320.o > diff --git a/drivers/extcon/extcon-usbc-tusb320.c > b/drivers/extcon/extcon-usbc-tusb320.c > new file mode 100644 > index 000000000000..217d6f416ff6 > --- /dev/null > +++ b/drivers/extcon/extcon-usbc-tusb320.c > @@ -0,0 +1,180 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/** > + * drivers/extcon/extcon-tusb320.c - TUSB320 extcon driver > + * > + * Copyright (C) 2020 National Instruments Corporation > + * Author: Michael Auchter <michael.auch...@ni.com> > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License version 2 as > + * published by the Free Software Foundation. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. You don't need to additional license info below 'author' because you added '// SPDX-License-Identifier: GPL-2.0' at the first line. > + */ > + > +#include <linux/extcon-provider.h> > +#include <linux/init.h> > +#include <linux/interrupt.h> > +#include <linux/i2c.h> > +#include <linux/irq.h> > +#include <linux/kernel.h> > +#include <linux/module.h> > +#include <linux/slab.h> > +#include <linux/workqueue.h> > + > +#define TUSB320_REG_9 0x9 > +#define TUSB320_REG_9_INTERRUPT_STATUS BIT(4) > +#define TUSB320_REG_9_GET_ATTACHED_STATE(reg) (((reg) >> 6) & 0x3) You need to define what is meaning of '6' and '0x3'. #define TUSB30_xxx_SHIFT 6 #define TUSB30_xxx_MASK 0x3 > +#define TUSB320_REG_9_GET_CABLE_DIR(reg) (((reg) >> 5) & 1) ditto. #define TUSB30_xxx__SHIFT 5 #define TUSB30_xxx_MASK 0x1 > +#define TUSB320_ATTACHED_STATE_NONE 0x0 > +#define TUSB320_ATTACHED_STATE_DFP 0x1 > +#define TUSB320_ATTACHED_STATE_UFP 0x2 > +#define TUSB320_ATTACHED_STATE_ACC 0x3 > + nitpick. For the indentation, how about editing as following: #define TUSB320_REG_9 0x9 #define TUSB320_REG_9_INTERRUPT_STATUS BIT(4) #define TUSB320_REG_9_GET_ATTACHED_STATE(reg) (((reg) >> 6) & 0x3) #define TUSB320_REG_9_GET_CABLE_DIR(reg) (((reg) >> 5) & 1) #define TUSB320_ATTACHED_STATE_NONE 0x0 #define TUSB320_ATTACHED_STATE_DFP 0x1 #define TUSB320_ATTACHED_STATE_UFP 0x2 #define TUSB320_ATTACHED_STATE_ACC 0x3 > +static const char * const tusb_attached_states[] = { > + [TUSB320_ATTACHED_STATE_NONE] = "not attached", > + [TUSB320_ATTACHED_STATE_DFP] = "downstream facing port", > + [TUSB320_ATTACHED_STATE_UFP] = "upstream facing port", > + [TUSB320_ATTACHED_STATE_ACC] = "accessory", > +}; > + > +static const unsigned int tusb320_extcon_cable[] = { > + EXTCON_USB, > + EXTCON_USB_HOST, > + EXTCON_NONE, > +}; > + > +static int tusb320_check_signature(struct i2c_client *client) > +{ > + static const char sig[] = { '\0', 'T', 'U', 'S', 'B', '3', '2', '0' }; > + int i, ret; > + > + for (i = 0; i < sizeof(sig); i++) { > + ret = i2c_smbus_read_byte_data(client, sizeof(sig) - 1 - i); > + if (ret < 0) > + return ret; > + if (ret != sig[i]) { > + dev_err(&client->dev, "signature mismatch!\n"); > + return -ENODEV; > + } > + } > + > + return 0; > +} > + > +static irqreturn_t tusb320_irq_handler(int irq, void *dev_id) > +{ > + struct i2c_client *client = dev_id; > + struct extcon_dev *edev = i2c_get_clientdata(client); > + int reg, state, polarity; > + > + reg = i2c_smbus_read_byte_data(client, TUSB320_REG_9); > + if (reg < 0) { > + dev_err(&client->dev, "error during i2c read: %d\n", reg); > + return IRQ_NONE; > + } > + > + if (!(reg & TUSB320_REG_9_INTERRUPT_STATUS)) > + return IRQ_NONE; > + > + state = TUSB320_REG_9_GET_ATTACHED_STATE(reg); > + polarity = TUSB320_REG_9_GET_CABLE_DIR(reg); > + > + dev_dbg(&client->dev, "attached state: %s, polarity: %d\n", > + tusb_attached_states[state], polarity); > + > + extcon_set_state(edev, EXTCON_USB, > + state == TUSB320_ATTACHED_STATE_UFP); > + extcon_set_state(edev, EXTCON_USB_HOST, > + state == TUSB320_ATTACHED_STATE_DFP); > + extcon_set_property(edev, EXTCON_USB, > + EXTCON_PROP_USB_TYPEC_POLARITY, > + (union extcon_property_value)polarity); > + extcon_set_property(edev, EXTCON_USB_HOST, > + EXTCON_PROP_USB_TYPEC_POLARITY, > + (union extcon_property_value)polarity); > + extcon_sync(edev, EXTCON_USB); > + extcon_sync(edev, EXTCON_USB_HOST); > + > + i2c_smbus_write_byte_data(client, TUSB320_REG_9, reg); > + > + return IRQ_HANDLED; > +} > + > +static int tusb320_extcon_probe(struct i2c_client *client, > + const struct i2c_device_id *id) > +{ > + struct extcon_dev *edev; > + int ret; I recommend that you better to use regmap_i2c with devm_regmap_init_i2c() function instead of using i2c_smbus_*() function. You can refer regmap_i2c usage on drivers/extcon/extcon-sm5502.c. > + > + ret = tusb320_check_signature(client); > + if (ret) > + return ret; > + > + edev = devm_extcon_dev_allocate(&client->dev, tusb320_extcon_cable); > + if (IS_ERR(edev)) { > + dev_err(&client->dev, "failed to allocate extcon device\n"); > + return -ENOMEM; > + } > + i2c_set_clientdata(client, edev); > + > + ret = devm_extcon_dev_register(&client->dev, edev); > + if (ret < 0) { > + dev_err(&client->dev, "failed to register extcon device\n"); > + return ret; > + } > + > + extcon_set_property_capability(edev, EXTCON_USB, > + EXTCON_PROP_USB_TYPEC_POLARITY); > + extcon_set_property_capability(edev, EXTCON_USB_HOST, > + EXTCON_PROP_USB_TYPEC_POLARITY); > + > + /* update initial state */ > + tusb320_irq_handler(client->irq, client); > + > + ret = devm_request_threaded_irq(&client->dev, client->irq, > + NULL, tusb320_irq_handler, > + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, > + dev_name(&client->dev), client); > + > + return ret; > +} > + > +static const struct of_device_id tusb320_extcon_dt_match[] = { > + { .compatible = "ti,tusb320", }, > + { } > +}; > +MODULE_DEVICE_TABLE(of, tusb320_extcon_dt_match); > + > +static const struct i2c_device_id tusb320_i2c_id[] = { > + { "tusb320", 0 }, > + { } > +}; > +MODULE_DEVICE_TABLE(i2c, tusb320_i2c_id); > + > +static struct i2c_driver tusb320_extcon_driver = { > + .probe = tusb320_extcon_probe, > + .driver = { > + .name = "extcon-tusb320", > + .of_match_table = tusb320_extcon_dt_match, > + }, > +}; > + > +static int __init tusb320_init(void) > +{ > + return i2c_add_driver(&tusb320_extcon_driver); > +} > +subsys_initcall(tusb320_init); > + > +static void __exit tusb320_exit(void) > +{ > + i2c_del_driver(&tusb320_extcon_driver); > +} > +module_exit(tusb320_exit); > + > +MODULE_AUTHOR("Michael Auchter <michael.auch...@ni.com>"); > +MODULE_DESCRIPTION("TI TUSB320 extcon driver"); > +MODULE_LICENSE("GPL v2"); > -- Best Regards, Chanwoo Choi Samsung Electronics