Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.18-rc6 464 lines 13 kB view raw
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 0x08 20#define HD3SS3220_REG_CN_STAT_CTRL 0x09 21#define HD3SS3220_REG_GEN_CTRL 0x0A 22#define HD3SS3220_REG_DEV_REV 0xA0 23 24/* Register HD3SS3220_REG_CN_STAT */ 25#define HD3SS3220_REG_CN_STAT_CURRENT_MODE_MASK (BIT(7) | BIT(6)) 26#define HD3SS3220_REG_CN_STAT_CURRENT_MODE_DEFAULT 0x00 27#define HD3SS3220_REG_CN_STAT_CURRENT_MODE_MID BIT(6) 28#define HD3SS3220_REG_CN_STAT_CURRENT_MODE_HIGH BIT(7) 29 30/* Register HD3SS3220_REG_CN_STAT_CTRL*/ 31#define HD3SS3220_REG_CN_STAT_CTRL_ATTACHED_STATE_MASK (BIT(7) | BIT(6)) 32#define HD3SS3220_REG_CN_STAT_CTRL_AS_DFP BIT(6) 33#define HD3SS3220_REG_CN_STAT_CTRL_AS_UFP BIT(7) 34#define HD3SS3220_REG_CN_STAT_CTRL_TO_ACCESSORY (BIT(7) | BIT(6)) 35#define HD3SS3220_REG_CN_STAT_CTRL_INT_STATUS BIT(4) 36 37/* Register HD3SS3220_REG_GEN_CTRL*/ 38#define HD3SS3220_REG_GEN_CTRL_DISABLE_TERM BIT(0) 39#define HD3SS3220_REG_GEN_CTRL_SRC_PREF_MASK (BIT(2) | BIT(1)) 40#define HD3SS3220_REG_GEN_CTRL_SRC_PREF_DRP_DEFAULT 0x00 41#define HD3SS3220_REG_GEN_CTRL_SRC_PREF_DRP_TRY_SNK BIT(1) 42#define HD3SS3220_REG_GEN_CTRL_SRC_PREF_DRP_TRY_SRC (BIT(2) | BIT(1)) 43#define HD3SS3220_REG_GEN_CTRL_MODE_SELECT_MASK (BIT(5) | BIT(4)) 44#define HD3SS3220_REG_GEN_CTRL_MODE_SELECT_DEFAULT 0x00 45#define HD3SS3220_REG_GEN_CTRL_MODE_SELECT_DFP BIT(5) 46#define HD3SS3220_REG_GEN_CTRL_MODE_SELECT_UFP BIT(4) 47#define HD3SS3220_REG_GEN_CTRL_MODE_SELECT_DRP (BIT(5) | BIT(4)) 48 49struct hd3ss3220 { 50 struct device *dev; 51 struct regmap *regmap; 52 struct usb_role_switch *role_sw; 53 struct typec_port *port; 54 struct delayed_work output_poll_work; 55 enum usb_role role_state; 56 bool poll; 57}; 58 59static int hd3ss3220_set_power_opmode(struct hd3ss3220 *hd3ss3220, int power_opmode) 60{ 61 int current_mode; 62 63 switch (power_opmode) { 64 case TYPEC_PWR_MODE_USB: 65 current_mode = HD3SS3220_REG_CN_STAT_CURRENT_MODE_DEFAULT; 66 break; 67 case TYPEC_PWR_MODE_1_5A: 68 current_mode = HD3SS3220_REG_CN_STAT_CURRENT_MODE_MID; 69 break; 70 case TYPEC_PWR_MODE_3_0A: 71 current_mode = HD3SS3220_REG_CN_STAT_CURRENT_MODE_HIGH; 72 break; 73 case TYPEC_PWR_MODE_PD: /* Power delivery not supported */ 74 default: 75 dev_err(hd3ss3220->dev, "bad power operation mode: %d\n", power_opmode); 76 return -EINVAL; 77 } 78 79 return regmap_update_bits(hd3ss3220->regmap, HD3SS3220_REG_CN_STAT, 80 HD3SS3220_REG_CN_STAT_CURRENT_MODE_MASK, 81 current_mode); 82} 83 84static int hd3ss3220_set_port_type(struct hd3ss3220 *hd3ss3220, int type) 85{ 86 int mode_select, err; 87 88 switch (type) { 89 case TYPEC_PORT_SRC: 90 mode_select = HD3SS3220_REG_GEN_CTRL_MODE_SELECT_DFP; 91 break; 92 case TYPEC_PORT_SNK: 93 mode_select = HD3SS3220_REG_GEN_CTRL_MODE_SELECT_UFP; 94 break; 95 case TYPEC_PORT_DRP: 96 mode_select = HD3SS3220_REG_GEN_CTRL_MODE_SELECT_DRP; 97 break; 98 default: 99 dev_err(hd3ss3220->dev, "bad port type: %d\n", type); 100 return -EINVAL; 101 } 102 103 /* Disable termination before changing MODE_SELECT as required by datasheet */ 104 err = regmap_update_bits(hd3ss3220->regmap, HD3SS3220_REG_GEN_CTRL, 105 HD3SS3220_REG_GEN_CTRL_DISABLE_TERM, 106 HD3SS3220_REG_GEN_CTRL_DISABLE_TERM); 107 if (err < 0) { 108 dev_err(hd3ss3220->dev, "Failed to disable port for mode change: %d\n", err); 109 return err; 110 } 111 112 err = regmap_update_bits(hd3ss3220->regmap, HD3SS3220_REG_GEN_CTRL, 113 HD3SS3220_REG_GEN_CTRL_MODE_SELECT_MASK, 114 mode_select); 115 if (err < 0) { 116 dev_err(hd3ss3220->dev, "Failed to change mode: %d\n", err); 117 regmap_update_bits(hd3ss3220->regmap, HD3SS3220_REG_GEN_CTRL, 118 HD3SS3220_REG_GEN_CTRL_DISABLE_TERM, 0); 119 return err; 120 } 121 122 err = regmap_update_bits(hd3ss3220->regmap, HD3SS3220_REG_GEN_CTRL, 123 HD3SS3220_REG_GEN_CTRL_DISABLE_TERM, 0); 124 if (err < 0) 125 dev_err(hd3ss3220->dev, "Failed to re-enable port after mode change: %d\n", err); 126 127 return err; 128} 129 130static int hd3ss3220_set_source_pref(struct hd3ss3220 *hd3ss3220, int prefer_role) 131{ 132 int src_pref; 133 134 switch (prefer_role) { 135 case TYPEC_NO_PREFERRED_ROLE: 136 src_pref = HD3SS3220_REG_GEN_CTRL_SRC_PREF_DRP_DEFAULT; 137 break; 138 case TYPEC_SINK: 139 src_pref = HD3SS3220_REG_GEN_CTRL_SRC_PREF_DRP_TRY_SNK; 140 break; 141 case TYPEC_SOURCE: 142 src_pref = HD3SS3220_REG_GEN_CTRL_SRC_PREF_DRP_TRY_SRC; 143 break; 144 default: 145 dev_err(hd3ss3220->dev, "bad role preference: %d\n", prefer_role); 146 return -EINVAL; 147 } 148 149 return regmap_update_bits(hd3ss3220->regmap, HD3SS3220_REG_GEN_CTRL, 150 HD3SS3220_REG_GEN_CTRL_SRC_PREF_MASK, 151 src_pref); 152} 153 154static enum usb_role hd3ss3220_get_attached_state(struct hd3ss3220 *hd3ss3220) 155{ 156 unsigned int reg_val; 157 enum usb_role attached_state; 158 int ret; 159 160 ret = regmap_read(hd3ss3220->regmap, HD3SS3220_REG_CN_STAT_CTRL, 161 &reg_val); 162 if (ret < 0) 163 return ret; 164 165 switch (reg_val & HD3SS3220_REG_CN_STAT_CTRL_ATTACHED_STATE_MASK) { 166 case HD3SS3220_REG_CN_STAT_CTRL_AS_DFP: 167 attached_state = USB_ROLE_HOST; 168 break; 169 case HD3SS3220_REG_CN_STAT_CTRL_AS_UFP: 170 attached_state = USB_ROLE_DEVICE; 171 break; 172 default: 173 attached_state = USB_ROLE_NONE; 174 break; 175 } 176 177 return attached_state; 178} 179 180static int hd3ss3220_try_role(struct typec_port *port, int role) 181{ 182 struct hd3ss3220 *hd3ss3220 = typec_get_drvdata(port); 183 184 return hd3ss3220_set_source_pref(hd3ss3220, role); 185} 186 187static int hd3ss3220_port_type_set(struct typec_port *port, enum typec_port_type type) 188{ 189 struct hd3ss3220 *hd3ss3220 = typec_get_drvdata(port); 190 191 return hd3ss3220_set_port_type(hd3ss3220, type); 192} 193 194static const struct typec_operations hd3ss3220_ops = { 195 .try_role = hd3ss3220_try_role, 196 .port_type_set = hd3ss3220_port_type_set, 197}; 198 199static void hd3ss3220_set_role(struct hd3ss3220 *hd3ss3220) 200{ 201 enum usb_role role_state = hd3ss3220_get_attached_state(hd3ss3220); 202 203 usb_role_switch_set_role(hd3ss3220->role_sw, role_state); 204 205 switch (role_state) { 206 case USB_ROLE_HOST: 207 typec_set_data_role(hd3ss3220->port, TYPEC_HOST); 208 break; 209 case USB_ROLE_DEVICE: 210 typec_set_data_role(hd3ss3220->port, TYPEC_DEVICE); 211 break; 212 default: 213 break; 214 } 215 216 hd3ss3220->role_state = role_state; 217} 218 219static void output_poll_execute(struct work_struct *work) 220{ 221 struct delayed_work *delayed_work = to_delayed_work(work); 222 struct hd3ss3220 *hd3ss3220 = container_of(delayed_work, 223 struct hd3ss3220, 224 output_poll_work); 225 enum usb_role role_state = hd3ss3220_get_attached_state(hd3ss3220); 226 227 if (hd3ss3220->role_state != role_state) 228 hd3ss3220_set_role(hd3ss3220); 229 230 schedule_delayed_work(&hd3ss3220->output_poll_work, HZ); 231} 232 233static irqreturn_t hd3ss3220_irq(struct hd3ss3220 *hd3ss3220) 234{ 235 int err; 236 237 hd3ss3220_set_role(hd3ss3220); 238 err = regmap_write_bits(hd3ss3220->regmap, HD3SS3220_REG_CN_STAT_CTRL, 239 HD3SS3220_REG_CN_STAT_CTRL_INT_STATUS, 240 HD3SS3220_REG_CN_STAT_CTRL_INT_STATUS); 241 if (err < 0) 242 return IRQ_NONE; 243 244 return IRQ_HANDLED; 245} 246 247static irqreturn_t hd3ss3220_irq_handler(int irq, void *data) 248{ 249 struct i2c_client *client = to_i2c_client(data); 250 struct hd3ss3220 *hd3ss3220 = i2c_get_clientdata(client); 251 252 return hd3ss3220_irq(hd3ss3220); 253} 254 255static int hd3ss3220_configure_power_opmode(struct hd3ss3220 *hd3ss3220, 256 struct fwnode_handle *connector) 257{ 258 /* 259 * Supported power operation mode can be configured through device tree 260 */ 261 const char *cap_str; 262 int ret, power_opmode; 263 264 ret = fwnode_property_read_string(connector, "typec-power-opmode", &cap_str); 265 if (ret) 266 return 0; 267 268 power_opmode = typec_find_pwr_opmode(cap_str); 269 return hd3ss3220_set_power_opmode(hd3ss3220, power_opmode); 270} 271 272static int hd3ss3220_configure_port_type(struct hd3ss3220 *hd3ss3220, 273 struct fwnode_handle *connector, 274 struct typec_capability *cap) 275{ 276 /* 277 * Port type can be configured through device tree 278 */ 279 const char *cap_str; 280 int ret; 281 282 ret = fwnode_property_read_string(connector, "power-role", &cap_str); 283 if (ret) 284 return 0; 285 286 ret = typec_find_port_power_role(cap_str); 287 if (ret < 0) 288 return ret; 289 290 cap->type = ret; 291 return hd3ss3220_set_port_type(hd3ss3220, cap->type); 292} 293 294static int hd3ss3220_configure_source_pref(struct hd3ss3220 *hd3ss3220, 295 struct fwnode_handle *connector, 296 struct typec_capability *cap) 297{ 298 /* 299 * Preferred role can be configured through device tree 300 */ 301 const char *cap_str; 302 int ret; 303 304 ret = fwnode_property_read_string(connector, "try-power-role", &cap_str); 305 if (ret) 306 return 0; 307 308 ret = typec_find_power_role(cap_str); 309 if (ret < 0) 310 return ret; 311 312 cap->prefer_role = ret; 313 return hd3ss3220_set_source_pref(hd3ss3220, cap->prefer_role); 314} 315 316static const struct regmap_config config = { 317 .reg_bits = 8, 318 .val_bits = 8, 319 .max_register = 0x0A, 320}; 321 322static int hd3ss3220_probe(struct i2c_client *client) 323{ 324 struct typec_capability typec_cap = { }; 325 struct hd3ss3220 *hd3ss3220; 326 struct fwnode_handle *connector, *ep; 327 int ret; 328 unsigned int data; 329 330 hd3ss3220 = devm_kzalloc(&client->dev, sizeof(struct hd3ss3220), 331 GFP_KERNEL); 332 if (!hd3ss3220) 333 return -ENOMEM; 334 335 i2c_set_clientdata(client, hd3ss3220); 336 337 hd3ss3220->dev = &client->dev; 338 hd3ss3220->regmap = devm_regmap_init_i2c(client, &config); 339 if (IS_ERR(hd3ss3220->regmap)) 340 return PTR_ERR(hd3ss3220->regmap); 341 342 /* For backward compatibility check the connector child node first */ 343 connector = device_get_named_child_node(hd3ss3220->dev, "connector"); 344 if (connector) { 345 hd3ss3220->role_sw = fwnode_usb_role_switch_get(connector); 346 } else { 347 ep = fwnode_graph_get_next_endpoint(dev_fwnode(hd3ss3220->dev), NULL); 348 if (!ep) 349 return -ENODEV; 350 connector = fwnode_graph_get_remote_port_parent(ep); 351 fwnode_handle_put(ep); 352 if (!connector) 353 return -ENODEV; 354 hd3ss3220->role_sw = usb_role_switch_get(hd3ss3220->dev); 355 } 356 357 if (IS_ERR(hd3ss3220->role_sw)) { 358 ret = PTR_ERR(hd3ss3220->role_sw); 359 goto err_put_fwnode; 360 } 361 362 typec_cap.prefer_role = TYPEC_NO_PREFERRED_ROLE; 363 typec_cap.driver_data = hd3ss3220; 364 typec_cap.type = TYPEC_PORT_DRP; 365 typec_cap.data = TYPEC_PORT_DRD; 366 typec_cap.ops = &hd3ss3220_ops; 367 typec_cap.fwnode = connector; 368 369 ret = hd3ss3220_configure_source_pref(hd3ss3220, connector, &typec_cap); 370 if (ret < 0) 371 goto err_put_role; 372 373 ret = hd3ss3220_configure_port_type(hd3ss3220, connector, &typec_cap); 374 if (ret < 0) 375 goto err_put_role; 376 377 hd3ss3220->port = typec_register_port(&client->dev, &typec_cap); 378 if (IS_ERR(hd3ss3220->port)) { 379 ret = PTR_ERR(hd3ss3220->port); 380 goto err_put_role; 381 } 382 383 ret = hd3ss3220_configure_power_opmode(hd3ss3220, connector); 384 if (ret < 0) 385 goto err_unreg_port; 386 387 hd3ss3220_set_role(hd3ss3220); 388 ret = regmap_read(hd3ss3220->regmap, HD3SS3220_REG_CN_STAT_CTRL, &data); 389 if (ret < 0) 390 goto err_unreg_port; 391 392 if (data & HD3SS3220_REG_CN_STAT_CTRL_INT_STATUS) { 393 ret = regmap_write(hd3ss3220->regmap, 394 HD3SS3220_REG_CN_STAT_CTRL, 395 data | HD3SS3220_REG_CN_STAT_CTRL_INT_STATUS); 396 if (ret < 0) 397 goto err_unreg_port; 398 } 399 400 if (client->irq > 0) { 401 ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, 402 hd3ss3220_irq_handler, 403 IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 404 "hd3ss3220", &client->dev); 405 if (ret) 406 goto err_unreg_port; 407 } else { 408 INIT_DELAYED_WORK(&hd3ss3220->output_poll_work, output_poll_execute); 409 hd3ss3220->poll = true; 410 } 411 412 ret = i2c_smbus_read_byte_data(client, HD3SS3220_REG_DEV_REV); 413 if (ret < 0) 414 goto err_unreg_port; 415 416 fwnode_handle_put(connector); 417 418 if (hd3ss3220->poll) 419 schedule_delayed_work(&hd3ss3220->output_poll_work, HZ); 420 421 dev_info(&client->dev, "probed revision=0x%x\n", ret); 422 423 return 0; 424err_unreg_port: 425 typec_unregister_port(hd3ss3220->port); 426err_put_role: 427 usb_role_switch_put(hd3ss3220->role_sw); 428err_put_fwnode: 429 fwnode_handle_put(connector); 430 431 return ret; 432} 433 434static void hd3ss3220_remove(struct i2c_client *client) 435{ 436 struct hd3ss3220 *hd3ss3220 = i2c_get_clientdata(client); 437 438 if (hd3ss3220->poll) 439 cancel_delayed_work_sync(&hd3ss3220->output_poll_work); 440 441 typec_unregister_port(hd3ss3220->port); 442 usb_role_switch_put(hd3ss3220->role_sw); 443} 444 445static const struct of_device_id dev_ids[] = { 446 { .compatible = "ti,hd3ss3220"}, 447 {} 448}; 449MODULE_DEVICE_TABLE(of, dev_ids); 450 451static struct i2c_driver hd3ss3220_driver = { 452 .driver = { 453 .name = "hd3ss3220", 454 .of_match_table = dev_ids, 455 }, 456 .probe = hd3ss3220_probe, 457 .remove = hd3ss3220_remove, 458}; 459 460module_i2c_driver(hd3ss3220_driver); 461 462MODULE_AUTHOR("Biju Das <biju.das@bp.renesas.com>"); 463MODULE_DESCRIPTION("TI HD3SS3220 DRP Port Controller Driver"); 464MODULE_LICENSE("GPL");