Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * TI HD3SS3220 Type-C DRP Port Controller Driver
0004  *
0005  * Copyright (C) 2019 Renesas Electronics Corp.
0006  */
0007 
0008 #include <linux/module.h>
0009 #include <linux/i2c.h>
0010 #include <linux/usb/role.h>
0011 #include <linux/irqreturn.h>
0012 #include <linux/interrupt.h>
0013 #include <linux/regmap.h>
0014 #include <linux/slab.h>
0015 #include <linux/usb/typec.h>
0016 #include <linux/delay.h>
0017 
0018 #define HD3SS3220_REG_CN_STAT_CTRL  0x09
0019 #define HD3SS3220_REG_GEN_CTRL      0x0A
0020 #define HD3SS3220_REG_DEV_REV       0xA0
0021 
0022 /* Register HD3SS3220_REG_CN_STAT_CTRL*/
0023 #define HD3SS3220_REG_CN_STAT_CTRL_ATTACHED_STATE_MASK  (BIT(7) | BIT(6))
0024 #define HD3SS3220_REG_CN_STAT_CTRL_AS_DFP       BIT(6)
0025 #define HD3SS3220_REG_CN_STAT_CTRL_AS_UFP       BIT(7)
0026 #define HD3SS3220_REG_CN_STAT_CTRL_TO_ACCESSORY     (BIT(7) | BIT(6))
0027 #define HD3SS3220_REG_CN_STAT_CTRL_INT_STATUS       BIT(4)
0028 
0029 /* Register HD3SS3220_REG_GEN_CTRL*/
0030 #define HD3SS3220_REG_GEN_CTRL_SRC_PREF_MASK        (BIT(2) | BIT(1))
0031 #define HD3SS3220_REG_GEN_CTRL_SRC_PREF_DRP_DEFAULT 0x00
0032 #define HD3SS3220_REG_GEN_CTRL_SRC_PREF_DRP_TRY_SNK BIT(1)
0033 #define HD3SS3220_REG_GEN_CTRL_SRC_PREF_DRP_TRY_SRC (BIT(2) | BIT(1))
0034 
0035 struct hd3ss3220 {
0036     struct device *dev;
0037     struct regmap *regmap;
0038     struct usb_role_switch  *role_sw;
0039     struct typec_port *port;
0040 };
0041 
0042 static int hd3ss3220_set_source_pref(struct hd3ss3220 *hd3ss3220, int src_pref)
0043 {
0044     return regmap_update_bits(hd3ss3220->regmap, HD3SS3220_REG_GEN_CTRL,
0045                   HD3SS3220_REG_GEN_CTRL_SRC_PREF_MASK,
0046                   src_pref);
0047 }
0048 
0049 static enum usb_role hd3ss3220_get_attached_state(struct hd3ss3220 *hd3ss3220)
0050 {
0051     unsigned int reg_val;
0052     enum usb_role attached_state;
0053     int ret;
0054 
0055     ret = regmap_read(hd3ss3220->regmap, HD3SS3220_REG_CN_STAT_CTRL,
0056               &reg_val);
0057     if (ret < 0)
0058         return ret;
0059 
0060     switch (reg_val & HD3SS3220_REG_CN_STAT_CTRL_ATTACHED_STATE_MASK) {
0061     case HD3SS3220_REG_CN_STAT_CTRL_AS_DFP:
0062         attached_state = USB_ROLE_HOST;
0063         break;
0064     case HD3SS3220_REG_CN_STAT_CTRL_AS_UFP:
0065         attached_state = USB_ROLE_DEVICE;
0066         break;
0067     default:
0068         attached_state = USB_ROLE_NONE;
0069         break;
0070     }
0071 
0072     return attached_state;
0073 }
0074 
0075 static int hd3ss3220_dr_set(struct typec_port *port, enum typec_data_role role)
0076 {
0077     struct hd3ss3220 *hd3ss3220 = typec_get_drvdata(port);
0078     enum usb_role role_val;
0079     int pref, ret = 0;
0080 
0081     if (role == TYPEC_HOST) {
0082         role_val = USB_ROLE_HOST;
0083         pref = HD3SS3220_REG_GEN_CTRL_SRC_PREF_DRP_TRY_SRC;
0084     } else {
0085         role_val = USB_ROLE_DEVICE;
0086         pref = HD3SS3220_REG_GEN_CTRL_SRC_PREF_DRP_TRY_SNK;
0087     }
0088 
0089     ret = hd3ss3220_set_source_pref(hd3ss3220, pref);
0090     usleep_range(10, 100);
0091 
0092     usb_role_switch_set_role(hd3ss3220->role_sw, role_val);
0093     typec_set_data_role(hd3ss3220->port, role);
0094 
0095     return ret;
0096 }
0097 
0098 static const struct typec_operations hd3ss3220_ops = {
0099     .dr_set = hd3ss3220_dr_set
0100 };
0101 
0102 static void hd3ss3220_set_role(struct hd3ss3220 *hd3ss3220)
0103 {
0104     enum usb_role role_state = hd3ss3220_get_attached_state(hd3ss3220);
0105 
0106     usb_role_switch_set_role(hd3ss3220->role_sw, role_state);
0107     if (role_state == USB_ROLE_NONE)
0108         hd3ss3220_set_source_pref(hd3ss3220,
0109                 HD3SS3220_REG_GEN_CTRL_SRC_PREF_DRP_DEFAULT);
0110 
0111     switch (role_state) {
0112     case USB_ROLE_HOST:
0113         typec_set_data_role(hd3ss3220->port, TYPEC_HOST);
0114         break;
0115     case USB_ROLE_DEVICE:
0116         typec_set_data_role(hd3ss3220->port, TYPEC_DEVICE);
0117         break;
0118     default:
0119         break;
0120     }
0121 }
0122 
0123 static irqreturn_t hd3ss3220_irq(struct hd3ss3220 *hd3ss3220)
0124 {
0125     int err;
0126 
0127     hd3ss3220_set_role(hd3ss3220);
0128     err = regmap_write_bits(hd3ss3220->regmap, HD3SS3220_REG_CN_STAT_CTRL,
0129                 HD3SS3220_REG_CN_STAT_CTRL_INT_STATUS,
0130                 HD3SS3220_REG_CN_STAT_CTRL_INT_STATUS);
0131     if (err < 0)
0132         return IRQ_NONE;
0133 
0134     return IRQ_HANDLED;
0135 }
0136 
0137 static irqreturn_t hd3ss3220_irq_handler(int irq, void *data)
0138 {
0139     struct i2c_client *client = to_i2c_client(data);
0140     struct hd3ss3220 *hd3ss3220 = i2c_get_clientdata(client);
0141 
0142     return hd3ss3220_irq(hd3ss3220);
0143 }
0144 
0145 static const struct regmap_config config = {
0146     .reg_bits = 8,
0147     .val_bits = 8,
0148     .max_register = 0x0A,
0149 };
0150 
0151 static int hd3ss3220_probe(struct i2c_client *client,
0152         const struct i2c_device_id *id)
0153 {
0154     struct typec_capability typec_cap = { };
0155     struct hd3ss3220 *hd3ss3220;
0156     struct fwnode_handle *connector, *ep;
0157     int ret;
0158     unsigned int data;
0159 
0160     hd3ss3220 = devm_kzalloc(&client->dev, sizeof(struct hd3ss3220),
0161                  GFP_KERNEL);
0162     if (!hd3ss3220)
0163         return -ENOMEM;
0164 
0165     i2c_set_clientdata(client, hd3ss3220);
0166 
0167     hd3ss3220->dev = &client->dev;
0168     hd3ss3220->regmap = devm_regmap_init_i2c(client, &config);
0169     if (IS_ERR(hd3ss3220->regmap))
0170         return PTR_ERR(hd3ss3220->regmap);
0171 
0172     hd3ss3220_set_source_pref(hd3ss3220,
0173                   HD3SS3220_REG_GEN_CTRL_SRC_PREF_DRP_DEFAULT);
0174     /* For backward compatibility check the connector child node first */
0175     connector = device_get_named_child_node(hd3ss3220->dev, "connector");
0176     if (connector) {
0177         hd3ss3220->role_sw = fwnode_usb_role_switch_get(connector);
0178     } else {
0179         ep = fwnode_graph_get_next_endpoint(dev_fwnode(hd3ss3220->dev), NULL);
0180         if (!ep)
0181             return -ENODEV;
0182         connector = fwnode_graph_get_remote_port_parent(ep);
0183         fwnode_handle_put(ep);
0184         if (!connector)
0185             return -ENODEV;
0186         hd3ss3220->role_sw = usb_role_switch_get(hd3ss3220->dev);
0187     }
0188 
0189     if (IS_ERR(hd3ss3220->role_sw)) {
0190         ret = PTR_ERR(hd3ss3220->role_sw);
0191         goto err_put_fwnode;
0192     }
0193 
0194     typec_cap.prefer_role = TYPEC_NO_PREFERRED_ROLE;
0195     typec_cap.driver_data = hd3ss3220;
0196     typec_cap.type = TYPEC_PORT_DRP;
0197     typec_cap.data = TYPEC_PORT_DRD;
0198     typec_cap.ops = &hd3ss3220_ops;
0199     typec_cap.fwnode = connector;
0200 
0201     hd3ss3220->port = typec_register_port(&client->dev, &typec_cap);
0202     if (IS_ERR(hd3ss3220->port)) {
0203         ret = PTR_ERR(hd3ss3220->port);
0204         goto err_put_role;
0205     }
0206 
0207     hd3ss3220_set_role(hd3ss3220);
0208     ret = regmap_read(hd3ss3220->regmap, HD3SS3220_REG_CN_STAT_CTRL, &data);
0209     if (ret < 0)
0210         goto err_unreg_port;
0211 
0212     if (data & HD3SS3220_REG_CN_STAT_CTRL_INT_STATUS) {
0213         ret = regmap_write(hd3ss3220->regmap,
0214                 HD3SS3220_REG_CN_STAT_CTRL,
0215                 data | HD3SS3220_REG_CN_STAT_CTRL_INT_STATUS);
0216         if (ret < 0)
0217             goto err_unreg_port;
0218     }
0219 
0220     if (client->irq > 0) {
0221         ret = devm_request_threaded_irq(&client->dev, client->irq, NULL,
0222                     hd3ss3220_irq_handler,
0223                     IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
0224                     "hd3ss3220", &client->dev);
0225         if (ret)
0226             goto err_unreg_port;
0227     }
0228 
0229     ret = i2c_smbus_read_byte_data(client, HD3SS3220_REG_DEV_REV);
0230     if (ret < 0)
0231         goto err_unreg_port;
0232 
0233     fwnode_handle_put(connector);
0234 
0235     dev_info(&client->dev, "probed revision=0x%x\n", ret);
0236 
0237     return 0;
0238 err_unreg_port:
0239     typec_unregister_port(hd3ss3220->port);
0240 err_put_role:
0241     usb_role_switch_put(hd3ss3220->role_sw);
0242 err_put_fwnode:
0243     fwnode_handle_put(connector);
0244 
0245     return ret;
0246 }
0247 
0248 static int hd3ss3220_remove(struct i2c_client *client)
0249 {
0250     struct hd3ss3220 *hd3ss3220 = i2c_get_clientdata(client);
0251 
0252     typec_unregister_port(hd3ss3220->port);
0253     usb_role_switch_put(hd3ss3220->role_sw);
0254 
0255     return 0;
0256 }
0257 
0258 static const struct of_device_id dev_ids[] = {
0259     { .compatible = "ti,hd3ss3220"},
0260     {}
0261 };
0262 MODULE_DEVICE_TABLE(of, dev_ids);
0263 
0264 static struct i2c_driver hd3ss3220_driver = {
0265     .driver = {
0266         .name = "hd3ss3220",
0267         .of_match_table = of_match_ptr(dev_ids),
0268     },
0269     .probe = hd3ss3220_probe,
0270     .remove =  hd3ss3220_remove,
0271 };
0272 
0273 module_i2c_driver(hd3ss3220_driver);
0274 
0275 MODULE_AUTHOR("Biju Das <biju.das@bp.renesas.com>");
0276 MODULE_DESCRIPTION("TI HD3SS3220 DRP Port Controller Driver");
0277 MODULE_LICENSE("GPL");