Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /**
0003  * drivers/extcon/extcon-tusb320.c - TUSB320 extcon driver
0004  *
0005  * Copyright (C) 2020 National Instruments Corporation
0006  * Author: Michael Auchter <michael.auchter@ni.com>
0007  */
0008 
0009 #include <linux/extcon-provider.h>
0010 #include <linux/i2c.h>
0011 #include <linux/init.h>
0012 #include <linux/interrupt.h>
0013 #include <linux/kernel.h>
0014 #include <linux/module.h>
0015 #include <linux/regmap.h>
0016 
0017 #define TUSB320_REG9                0x9
0018 #define TUSB320_REG9_ATTACHED_STATE_SHIFT   6
0019 #define TUSB320_REG9_ATTACHED_STATE_MASK    0x3
0020 #define TUSB320_REG9_CABLE_DIRECTION        BIT(5)
0021 #define TUSB320_REG9_INTERRUPT_STATUS       BIT(4)
0022 
0023 #define TUSB320_REGA                0xa
0024 #define TUSB320L_REGA_DISABLE_TERM      BIT(0)
0025 #define TUSB320_REGA_I2C_SOFT_RESET     BIT(3)
0026 #define TUSB320_REGA_MODE_SELECT_SHIFT      4
0027 #define TUSB320_REGA_MODE_SELECT_MASK       0x3
0028 
0029 #define TUSB320L_REGA0_REVISION         0xa0
0030 
0031 enum tusb320_attached_state {
0032     TUSB320_ATTACHED_STATE_NONE,
0033     TUSB320_ATTACHED_STATE_DFP,
0034     TUSB320_ATTACHED_STATE_UFP,
0035     TUSB320_ATTACHED_STATE_ACC,
0036 };
0037 
0038 enum tusb320_mode {
0039     TUSB320_MODE_PORT,
0040     TUSB320_MODE_UFP,
0041     TUSB320_MODE_DFP,
0042     TUSB320_MODE_DRP,
0043 };
0044 
0045 struct tusb320_priv;
0046 
0047 struct tusb320_ops {
0048     int (*set_mode)(struct tusb320_priv *priv, enum tusb320_mode mode);
0049     int (*get_revision)(struct tusb320_priv *priv, unsigned int *revision);
0050 };
0051 
0052 struct tusb320_priv {
0053     struct device *dev;
0054     struct regmap *regmap;
0055     struct extcon_dev *edev;
0056     struct tusb320_ops *ops;
0057     enum tusb320_attached_state state;
0058 };
0059 
0060 static const char * const tusb_attached_states[] = {
0061     [TUSB320_ATTACHED_STATE_NONE] = "not attached",
0062     [TUSB320_ATTACHED_STATE_DFP]  = "downstream facing port",
0063     [TUSB320_ATTACHED_STATE_UFP]  = "upstream facing port",
0064     [TUSB320_ATTACHED_STATE_ACC]  = "accessory",
0065 };
0066 
0067 static const unsigned int tusb320_extcon_cable[] = {
0068     EXTCON_USB,
0069     EXTCON_USB_HOST,
0070     EXTCON_NONE,
0071 };
0072 
0073 static int tusb320_check_signature(struct tusb320_priv *priv)
0074 {
0075     static const char sig[] = { '\0', 'T', 'U', 'S', 'B', '3', '2', '0' };
0076     unsigned val;
0077     int i, ret;
0078 
0079     for (i = 0; i < sizeof(sig); i++) {
0080         ret = regmap_read(priv->regmap, sizeof(sig) - 1 - i, &val);
0081         if (ret < 0)
0082             return ret;
0083         if (val != sig[i]) {
0084             dev_err(priv->dev, "signature mismatch!\n");
0085             return -ENODEV;
0086         }
0087     }
0088 
0089     return 0;
0090 }
0091 
0092 static int tusb320_set_mode(struct tusb320_priv *priv, enum tusb320_mode mode)
0093 {
0094     int ret;
0095 
0096     /* Mode cannot be changed while cable is attached */
0097     if (priv->state != TUSB320_ATTACHED_STATE_NONE)
0098         return -EBUSY;
0099 
0100     /* Write mode */
0101     ret = regmap_write_bits(priv->regmap, TUSB320_REGA,
0102         TUSB320_REGA_MODE_SELECT_MASK << TUSB320_REGA_MODE_SELECT_SHIFT,
0103         mode << TUSB320_REGA_MODE_SELECT_SHIFT);
0104     if (ret) {
0105         dev_err(priv->dev, "failed to write mode: %d\n", ret);
0106         return ret;
0107     }
0108 
0109     return 0;
0110 }
0111 
0112 static int tusb320l_set_mode(struct tusb320_priv *priv, enum tusb320_mode mode)
0113 {
0114     int ret;
0115 
0116     /* Disable CC state machine */
0117     ret = regmap_write_bits(priv->regmap, TUSB320_REGA,
0118         TUSB320L_REGA_DISABLE_TERM, 1);
0119     if (ret) {
0120         dev_err(priv->dev,
0121             "failed to disable CC state machine: %d\n", ret);
0122         return ret;
0123     }
0124 
0125     /* Write mode */
0126     ret = regmap_write_bits(priv->regmap, TUSB320_REGA,
0127         TUSB320_REGA_MODE_SELECT_MASK << TUSB320_REGA_MODE_SELECT_SHIFT,
0128         mode << TUSB320_REGA_MODE_SELECT_SHIFT);
0129     if (ret) {
0130         dev_err(priv->dev, "failed to write mode: %d\n", ret);
0131         goto err;
0132     }
0133 
0134     msleep(5);
0135 err:
0136     /* Re-enable CC state machine */
0137     ret = regmap_write_bits(priv->regmap, TUSB320_REGA,
0138         TUSB320L_REGA_DISABLE_TERM, 0);
0139     if (ret)
0140         dev_err(priv->dev,
0141             "failed to re-enable CC state machine: %d\n", ret);
0142 
0143     return ret;
0144 }
0145 
0146 static int tusb320_reset(struct tusb320_priv *priv)
0147 {
0148     int ret;
0149 
0150     /* Set mode to default (follow PORT pin) */
0151     ret = priv->ops->set_mode(priv, TUSB320_MODE_PORT);
0152     if (ret && ret != -EBUSY) {
0153         dev_err(priv->dev,
0154             "failed to set mode to PORT: %d\n", ret);
0155         return ret;
0156     }
0157 
0158     /* Perform soft reset */
0159     ret = regmap_write_bits(priv->regmap, TUSB320_REGA,
0160             TUSB320_REGA_I2C_SOFT_RESET, 1);
0161     if (ret) {
0162         dev_err(priv->dev,
0163             "failed to write soft reset bit: %d\n", ret);
0164         return ret;
0165     }
0166 
0167     /* Wait for chip to go through reset */
0168     msleep(95);
0169 
0170     return 0;
0171 }
0172 
0173 static int tusb320l_get_revision(struct tusb320_priv *priv, unsigned int *revision)
0174 {
0175     return regmap_read(priv->regmap, TUSB320L_REGA0_REVISION, revision);
0176 }
0177 
0178 static struct tusb320_ops tusb320_ops = {
0179     .set_mode = tusb320_set_mode,
0180 };
0181 
0182 static struct tusb320_ops tusb320l_ops = {
0183     .set_mode = tusb320l_set_mode,
0184     .get_revision = tusb320l_get_revision,
0185 };
0186 
0187 static irqreturn_t tusb320_irq_handler(int irq, void *dev_id)
0188 {
0189     struct tusb320_priv *priv = dev_id;
0190     int state, polarity;
0191     unsigned reg;
0192 
0193     if (regmap_read(priv->regmap, TUSB320_REG9, &reg)) {
0194         dev_err(priv->dev, "error during i2c read!\n");
0195         return IRQ_NONE;
0196     }
0197 
0198     if (!(reg & TUSB320_REG9_INTERRUPT_STATUS))
0199         return IRQ_NONE;
0200 
0201     state = (reg >> TUSB320_REG9_ATTACHED_STATE_SHIFT) &
0202         TUSB320_REG9_ATTACHED_STATE_MASK;
0203     polarity = !!(reg & TUSB320_REG9_CABLE_DIRECTION);
0204 
0205     dev_dbg(priv->dev, "attached state: %s, polarity: %d\n",
0206         tusb_attached_states[state], polarity);
0207 
0208     extcon_set_state(priv->edev, EXTCON_USB,
0209              state == TUSB320_ATTACHED_STATE_UFP);
0210     extcon_set_state(priv->edev, EXTCON_USB_HOST,
0211              state == TUSB320_ATTACHED_STATE_DFP);
0212     extcon_set_property(priv->edev, EXTCON_USB,
0213                 EXTCON_PROP_USB_TYPEC_POLARITY,
0214                 (union extcon_property_value)polarity);
0215     extcon_set_property(priv->edev, EXTCON_USB_HOST,
0216                 EXTCON_PROP_USB_TYPEC_POLARITY,
0217                 (union extcon_property_value)polarity);
0218     extcon_sync(priv->edev, EXTCON_USB);
0219     extcon_sync(priv->edev, EXTCON_USB_HOST);
0220 
0221     priv->state = state;
0222 
0223     regmap_write(priv->regmap, TUSB320_REG9, reg);
0224 
0225     return IRQ_HANDLED;
0226 }
0227 
0228 static const struct regmap_config tusb320_regmap_config = {
0229     .reg_bits = 8,
0230     .val_bits = 8,
0231 };
0232 
0233 static int tusb320_extcon_probe(struct i2c_client *client,
0234                 const struct i2c_device_id *id)
0235 {
0236     struct tusb320_priv *priv;
0237     const void *match_data;
0238     unsigned int revision;
0239     int ret;
0240 
0241     priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
0242     if (!priv)
0243         return -ENOMEM;
0244     priv->dev = &client->dev;
0245 
0246     priv->regmap = devm_regmap_init_i2c(client, &tusb320_regmap_config);
0247     if (IS_ERR(priv->regmap))
0248         return PTR_ERR(priv->regmap);
0249 
0250     ret = tusb320_check_signature(priv);
0251     if (ret)
0252         return ret;
0253 
0254     match_data = device_get_match_data(&client->dev);
0255     if (!match_data)
0256         return -EINVAL;
0257 
0258     priv->ops = (struct tusb320_ops*)match_data;
0259 
0260     priv->edev = devm_extcon_dev_allocate(priv->dev, tusb320_extcon_cable);
0261     if (IS_ERR(priv->edev)) {
0262         dev_err(priv->dev, "failed to allocate extcon device\n");
0263         return PTR_ERR(priv->edev);
0264     }
0265 
0266     if (priv->ops->get_revision) {
0267         ret = priv->ops->get_revision(priv, &revision);
0268         if (ret)
0269             dev_warn(priv->dev,
0270                 "failed to read revision register: %d\n", ret);
0271         else
0272             dev_info(priv->dev, "chip revision %d\n", revision);
0273     }
0274 
0275     ret = devm_extcon_dev_register(priv->dev, priv->edev);
0276     if (ret < 0) {
0277         dev_err(priv->dev, "failed to register extcon device\n");
0278         return ret;
0279     }
0280 
0281     extcon_set_property_capability(priv->edev, EXTCON_USB,
0282                        EXTCON_PROP_USB_TYPEC_POLARITY);
0283     extcon_set_property_capability(priv->edev, EXTCON_USB_HOST,
0284                        EXTCON_PROP_USB_TYPEC_POLARITY);
0285 
0286     /* update initial state */
0287     tusb320_irq_handler(client->irq, priv);
0288 
0289     /* Reset chip to its default state */
0290     ret = tusb320_reset(priv);
0291     if (ret)
0292         dev_warn(priv->dev, "failed to reset chip: %d\n", ret);
0293     else
0294         /*
0295          * State and polarity might change after a reset, so update
0296          * them again and make sure the interrupt status bit is cleared.
0297          */
0298         tusb320_irq_handler(client->irq, priv);
0299 
0300     ret = devm_request_threaded_irq(priv->dev, client->irq, NULL,
0301                     tusb320_irq_handler,
0302                     IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
0303                     client->name, priv);
0304 
0305     return ret;
0306 }
0307 
0308 static const struct of_device_id tusb320_extcon_dt_match[] = {
0309     { .compatible = "ti,tusb320", .data = &tusb320_ops, },
0310     { .compatible = "ti,tusb320l", .data = &tusb320l_ops, },
0311     { }
0312 };
0313 MODULE_DEVICE_TABLE(of, tusb320_extcon_dt_match);
0314 
0315 static struct i2c_driver tusb320_extcon_driver = {
0316     .probe      = tusb320_extcon_probe,
0317     .driver     = {
0318         .name   = "extcon-tusb320",
0319         .of_match_table = tusb320_extcon_dt_match,
0320     },
0321 };
0322 
0323 static int __init tusb320_init(void)
0324 {
0325     return i2c_add_driver(&tusb320_extcon_driver);
0326 }
0327 subsys_initcall(tusb320_init);
0328 
0329 static void __exit tusb320_exit(void)
0330 {
0331     i2c_del_driver(&tusb320_extcon_driver);
0332 }
0333 module_exit(tusb320_exit);
0334 
0335 MODULE_AUTHOR("Michael Auchter <michael.auchter@ni.com>");
0336 MODULE_DESCRIPTION("TI TUSB320 extcon driver");
0337 MODULE_LICENSE("GPL v2");