1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * TI HD3SS3220 Type-C DRP Port Controller Driver 4 * 5 * Copyright (C) 2019 Renesas Electronics Corp. 6 */ 7 8#include <linux/module.h> 9#include <linux/i2c.h> 10#include <linux/usb/role.h> 11#include <linux/irqreturn.h> 12#include <linux/interrupt.h> 13#include <linux/regmap.h> 14#include <linux/slab.h> 15#include <linux/usb/typec.h> 16#include <linux/delay.h> 17#include <linux/workqueue.h> 18 19#define HD3SS3220_REG_CN_STAT_CTRL 0x09 20#define HD3SS3220_REG_GEN_CTRL 0x0A 21#define HD3SS3220_REG_DEV_REV 0xA0 22 23/* Register HD3SS3220_REG_CN_STAT_CTRL*/ 24#define HD3SS3220_REG_CN_STAT_CTRL_ATTACHED_STATE_MASK (BIT(7) | BIT(6)) 25#define HD3SS3220_REG_CN_STAT_CTRL_AS_DFP BIT(6) 26#define HD3SS3220_REG_CN_STAT_CTRL_AS_UFP BIT(7) 27#define HD3SS3220_REG_CN_STAT_CTRL_TO_ACCESSORY (BIT(7) | BIT(6)) 28#define HD3SS3220_REG_CN_STAT_CTRL_INT_STATUS BIT(4) 29 30/* Register HD3SS3220_REG_GEN_CTRL*/ 31#define HD3SS3220_REG_GEN_CTRL_SRC_PREF_MASK (BIT(2) | BIT(1)) 32#define HD3SS3220_REG_GEN_CTRL_SRC_PREF_DRP_DEFAULT 0x00 33#define HD3SS3220_REG_GEN_CTRL_SRC_PREF_DRP_TRY_SNK BIT(1) 34#define HD3SS3220_REG_GEN_CTRL_SRC_PREF_DRP_TRY_SRC (BIT(2) | BIT(1)) 35 36struct hd3ss3220 { 37 struct device *dev; 38 struct regmap *regmap; 39 struct usb_role_switch *role_sw; 40 struct typec_port *port; 41 struct delayed_work output_poll_work; 42 enum usb_role role_state; 43 bool poll; 44}; 45 46static int hd3ss3220_set_source_pref(struct hd3ss3220 *hd3ss3220, int src_pref) 47{ 48 return regmap_update_bits(hd3ss3220->regmap, HD3SS3220_REG_GEN_CTRL, 49 HD3SS3220_REG_GEN_CTRL_SRC_PREF_MASK, 50 src_pref); 51} 52 53static enum usb_role hd3ss3220_get_attached_state(struct hd3ss3220 *hd3ss3220) 54{ 55 unsigned int reg_val; 56 enum usb_role attached_state; 57 int ret; 58 59 ret = regmap_read(hd3ss3220->regmap, HD3SS3220_REG_CN_STAT_CTRL, 60 ®_val); 61 if (ret < 0) 62 return ret; 63 64 switch (reg_val & HD3SS3220_REG_CN_STAT_CTRL_ATTACHED_STATE_MASK) { 65 case HD3SS3220_REG_CN_STAT_CTRL_AS_DFP: 66 attached_state = USB_ROLE_HOST; 67 break; 68 case HD3SS3220_REG_CN_STAT_CTRL_AS_UFP: 69 attached_state = USB_ROLE_DEVICE; 70 break; 71 default: 72 attached_state = USB_ROLE_NONE; 73 break; 74 } 75 76 return attached_state; 77} 78 79static int hd3ss3220_dr_set(struct typec_port *port, enum typec_data_role role) 80{ 81 struct hd3ss3220 *hd3ss3220 = typec_get_drvdata(port); 82 enum usb_role role_val; 83 int pref, ret = 0; 84 85 if (role == TYPEC_HOST) { 86 role_val = USB_ROLE_HOST; 87 pref = HD3SS3220_REG_GEN_CTRL_SRC_PREF_DRP_TRY_SRC; 88 } else { 89 role_val = USB_ROLE_DEVICE; 90 pref = HD3SS3220_REG_GEN_CTRL_SRC_PREF_DRP_TRY_SNK; 91 } 92 93 ret = hd3ss3220_set_source_pref(hd3ss3220, pref); 94 usleep_range(10, 100); 95 96 usb_role_switch_set_role(hd3ss3220->role_sw, role_val); 97 typec_set_data_role(hd3ss3220->port, role); 98 99 return ret; 100} 101 102static const struct typec_operations hd3ss3220_ops = { 103 .dr_set = hd3ss3220_dr_set 104}; 105 106static void hd3ss3220_set_role(struct hd3ss3220 *hd3ss3220) 107{ 108 enum usb_role role_state = hd3ss3220_get_attached_state(hd3ss3220); 109 110 usb_role_switch_set_role(hd3ss3220->role_sw, role_state); 111 if (role_state == USB_ROLE_NONE) 112 hd3ss3220_set_source_pref(hd3ss3220, 113 HD3SS3220_REG_GEN_CTRL_SRC_PREF_DRP_DEFAULT); 114 115 switch (role_state) { 116 case USB_ROLE_HOST: 117 typec_set_data_role(hd3ss3220->port, TYPEC_HOST); 118 break; 119 case USB_ROLE_DEVICE: 120 typec_set_data_role(hd3ss3220->port, TYPEC_DEVICE); 121 break; 122 default: 123 break; 124 } 125 126 hd3ss3220->role_state = role_state; 127} 128 129static void output_poll_execute(struct work_struct *work) 130{ 131 struct delayed_work *delayed_work = to_delayed_work(work); 132 struct hd3ss3220 *hd3ss3220 = container_of(delayed_work, 133 struct hd3ss3220, 134 output_poll_work); 135 enum usb_role role_state = hd3ss3220_get_attached_state(hd3ss3220); 136 137 if (hd3ss3220->role_state != role_state) 138 hd3ss3220_set_role(hd3ss3220); 139 140 schedule_delayed_work(&hd3ss3220->output_poll_work, HZ); 141} 142 143static irqreturn_t hd3ss3220_irq(struct hd3ss3220 *hd3ss3220) 144{ 145 int err; 146 147 hd3ss3220_set_role(hd3ss3220); 148 err = regmap_write_bits(hd3ss3220->regmap, HD3SS3220_REG_CN_STAT_CTRL, 149 HD3SS3220_REG_CN_STAT_CTRL_INT_STATUS, 150 HD3SS3220_REG_CN_STAT_CTRL_INT_STATUS); 151 if (err < 0) 152 return IRQ_NONE; 153 154 return IRQ_HANDLED; 155} 156 157static irqreturn_t hd3ss3220_irq_handler(int irq, void *data) 158{ 159 struct i2c_client *client = to_i2c_client(data); 160 struct hd3ss3220 *hd3ss3220 = i2c_get_clientdata(client); 161 162 return hd3ss3220_irq(hd3ss3220); 163} 164 165static const struct regmap_config config = { 166 .reg_bits = 8, 167 .val_bits = 8, 168 .max_register = 0x0A, 169}; 170 171static int hd3ss3220_probe(struct i2c_client *client) 172{ 173 struct typec_capability typec_cap = { }; 174 struct hd3ss3220 *hd3ss3220; 175 struct fwnode_handle *connector, *ep; 176 int ret; 177 unsigned int data; 178 179 hd3ss3220 = devm_kzalloc(&client->dev, sizeof(struct hd3ss3220), 180 GFP_KERNEL); 181 if (!hd3ss3220) 182 return -ENOMEM; 183 184 i2c_set_clientdata(client, hd3ss3220); 185 186 hd3ss3220->dev = &client->dev; 187 hd3ss3220->regmap = devm_regmap_init_i2c(client, &config); 188 if (IS_ERR(hd3ss3220->regmap)) 189 return PTR_ERR(hd3ss3220->regmap); 190 191 hd3ss3220_set_source_pref(hd3ss3220, 192 HD3SS3220_REG_GEN_CTRL_SRC_PREF_DRP_DEFAULT); 193 /* For backward compatibility check the connector child node first */ 194 connector = device_get_named_child_node(hd3ss3220->dev, "connector"); 195 if (connector) { 196 hd3ss3220->role_sw = fwnode_usb_role_switch_get(connector); 197 } else { 198 ep = fwnode_graph_get_next_endpoint(dev_fwnode(hd3ss3220->dev), NULL); 199 if (!ep) 200 return -ENODEV; 201 connector = fwnode_graph_get_remote_port_parent(ep); 202 fwnode_handle_put(ep); 203 if (!connector) 204 return -ENODEV; 205 hd3ss3220->role_sw = usb_role_switch_get(hd3ss3220->dev); 206 } 207 208 if (IS_ERR(hd3ss3220->role_sw)) { 209 ret = PTR_ERR(hd3ss3220->role_sw); 210 goto err_put_fwnode; 211 } 212 213 typec_cap.prefer_role = TYPEC_NO_PREFERRED_ROLE; 214 typec_cap.driver_data = hd3ss3220; 215 typec_cap.type = TYPEC_PORT_DRP; 216 typec_cap.data = TYPEC_PORT_DRD; 217 typec_cap.ops = &hd3ss3220_ops; 218 typec_cap.fwnode = connector; 219 220 hd3ss3220->port = typec_register_port(&client->dev, &typec_cap); 221 if (IS_ERR(hd3ss3220->port)) { 222 ret = PTR_ERR(hd3ss3220->port); 223 goto err_put_role; 224 } 225 226 hd3ss3220_set_role(hd3ss3220); 227 ret = regmap_read(hd3ss3220->regmap, HD3SS3220_REG_CN_STAT_CTRL, &data); 228 if (ret < 0) 229 goto err_unreg_port; 230 231 if (data & HD3SS3220_REG_CN_STAT_CTRL_INT_STATUS) { 232 ret = regmap_write(hd3ss3220->regmap, 233 HD3SS3220_REG_CN_STAT_CTRL, 234 data | HD3SS3220_REG_CN_STAT_CTRL_INT_STATUS); 235 if (ret < 0) 236 goto err_unreg_port; 237 } 238 239 if (client->irq > 0) { 240 ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, 241 hd3ss3220_irq_handler, 242 IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 243 "hd3ss3220", &client->dev); 244 if (ret) 245 goto err_unreg_port; 246 } else { 247 INIT_DELAYED_WORK(&hd3ss3220->output_poll_work, output_poll_execute); 248 hd3ss3220->poll = true; 249 } 250 251 ret = i2c_smbus_read_byte_data(client, HD3SS3220_REG_DEV_REV); 252 if (ret < 0) 253 goto err_unreg_port; 254 255 fwnode_handle_put(connector); 256 257 if (hd3ss3220->poll) 258 schedule_delayed_work(&hd3ss3220->output_poll_work, HZ); 259 260 dev_info(&client->dev, "probed revision=0x%x\n", ret); 261 262 return 0; 263err_unreg_port: 264 typec_unregister_port(hd3ss3220->port); 265err_put_role: 266 usb_role_switch_put(hd3ss3220->role_sw); 267err_put_fwnode: 268 fwnode_handle_put(connector); 269 270 return ret; 271} 272 273static void hd3ss3220_remove(struct i2c_client *client) 274{ 275 struct hd3ss3220 *hd3ss3220 = i2c_get_clientdata(client); 276 277 if (hd3ss3220->poll) 278 cancel_delayed_work_sync(&hd3ss3220->output_poll_work); 279 280 typec_unregister_port(hd3ss3220->port); 281 usb_role_switch_put(hd3ss3220->role_sw); 282} 283 284static const struct of_device_id dev_ids[] = { 285 { .compatible = "ti,hd3ss3220"}, 286 {} 287}; 288MODULE_DEVICE_TABLE(of, dev_ids); 289 290static struct i2c_driver hd3ss3220_driver = { 291 .driver = { 292 .name = "hd3ss3220", 293 .of_match_table = dev_ids, 294 }, 295 .probe = hd3ss3220_probe, 296 .remove = hd3ss3220_remove, 297}; 298 299module_i2c_driver(hd3ss3220_driver); 300 301MODULE_AUTHOR("Biju Das <biju.das@bp.renesas.com>"); 302MODULE_DESCRIPTION("TI HD3SS3220 DRP Port Controller Driver"); 303MODULE_LICENSE("GPL"); 304