| 1 | |
| 2 |
|
| 3 | #include <linux/bitfield.h>
|
| 4 | #include <linux/completion.h>
|
| 5 | #include <linux/i2c.h>
|
| 6 | #include <linux/interrupt.h>
|
| 7 | #include <linux/kernel.h>
|
| 8 | #include <linux/module.h>
|
| 9 | #include <linux/power_supply.h>
|
| 10 | #include <linux/regmap.h>
|
| 11 | #include <linux/usb/pd.h>
|
| 12 | #include <linux/usb/role.h>
|
| 13 | #include <linux/usb/typec.h>
|
| 14 |
|
| 15 | #define RT1719_REG_TXCTRL1 0x03
|
| 16 | #define RT1719_REG_TXCTRL2 0x04
|
| 17 | #define RT1719_REG_POLICYINFO 0x0E
|
| 18 | #define RT1719_REG_SRCPDO1 0x11
|
| 19 | #define RT1719_REG_MASKS 0x2D
|
| 20 | #define RT1719_REG_EVENTS 0x33
|
| 21 | #define RT1719_REG_STATS 0x37
|
| 22 | #define RT1719_REG_PSELINFO 0x3C
|
| 23 | #define RT1719_REG_USBSETINFO 0x3E
|
| 24 | #define RT1719_REG_VENID 0x82
|
| 25 |
|
| 26 | #define RT1719_UNIQUE_PID 0x1719
|
| 27 | #define RT1719_REQDRSWAP_MASK BIT(7)
|
| 28 | #define RT1719_EVALMODE_MASK BIT(4)
|
| 29 | #define RT1719_REQSRCPDO_MASK GENMASK(2, 0)
|
| 30 | #define RT1719_TXSPDOREQ_MASK BIT(7)
|
| 31 | #define RT1719_INT_DRSW_ACCEPT BIT(23)
|
| 32 | #define RT1719_INT_RX_SRCCAP BIT(21)
|
| 33 | #define RT1719_INT_VBUS_DCT BIT(6)
|
| 34 | #define RT1719_INT_VBUS_PRESENT BIT(5)
|
| 35 | #define RT1719_INT_PE_SNK_RDY BIT(2)
|
| 36 | #define RT1719_CC1_STAT GENMASK(9, 8)
|
| 37 | #define RT1719_CC2_STAT GENMASK(11, 10)
|
| 38 | #define RT1719_POLARITY_MASK BIT(23)
|
| 39 | #define RT1719_DATAROLE_MASK BIT(22)
|
| 40 | #define RT1719_PDSPECREV_MASK GENMASK(21, 20)
|
| 41 | #define RT1719_SPDOSEL_MASK GENMASK(18, 16)
|
| 42 | #define RT1719_SPDONUM_MASK GENMASK(15, 13)
|
| 43 | #define RT1719_ATTACH_VBUS BIT(12)
|
| 44 | #define RT1719_ATTACH_DBG BIT(10)
|
| 45 | #define RT1719_ATTACH_SNK BIT(9)
|
| 46 | #define RT1719_ATTACHDEV_MASK (RT1719_ATTACH_VBUS | RT1719_ATTACH_DBG | \
|
| 47 | RT1719_ATTACH_SNK)
|
| 48 | #define RT1719_PE_EXP_CONTRACT BIT(2)
|
| 49 | #define RT1719_PSEL_SUPPORT BIT(15)
|
| 50 | #define RT1719_TBLSEL_MASK BIT(6)
|
| 51 | #define RT1719_LATPSEL_MASK GENMASK(5, 0)
|
| 52 | #define RT1719_USBINFO_MASK GENMASK(1, 0)
|
| 53 | #define RT1719_USB_DFPUFP 3
|
| 54 | #define RT1719_MAX_SRCPDO 7
|
| 55 |
|
| 56 | enum {
|
| 57 | SNK_PWR_OPEN = 0,
|
| 58 | SNK_PWR_DEF,
|
| 59 | SNK_PWR_1P5A,
|
| 60 | SNK_PWR_3A
|
| 61 | };
|
| 62 |
|
| 63 | enum {
|
| 64 | USBPD_SPECREV_1_0 = 0,
|
| 65 | USBPD_SPECREV_2_0,
|
| 66 | USBPD_SPECREV_3_0
|
| 67 | };
|
| 68 |
|
| 69 | enum rt1719_snkcap {
|
| 70 | RT1719_SNKCAP_5V = 0,
|
| 71 | RT1719_SNKCAP_9V,
|
| 72 | RT1719_SNKCAP_12V,
|
| 73 | RT1719_SNKCAP_15V,
|
| 74 | RT1719_SNKCAP_20V,
|
| 75 | RT1719_MAX_SNKCAP
|
| 76 | };
|
| 77 |
|
| 78 | struct rt1719_psel_cap {
|
| 79 | u8 lomask;
|
| 80 | u8 himask;
|
| 81 | u32 milliwatt;
|
| 82 | u32 milliamp;
|
| 83 | };
|
| 84 |
|
| 85 | struct rt1719_data {
|
| 86 | struct device *dev;
|
| 87 | struct regmap *regmap;
|
| 88 | struct typec_port *port;
|
| 89 | struct usb_role_switch *role_sw;
|
| 90 | struct power_supply *psy;
|
| 91 | struct typec_partner *partner;
|
| 92 | struct power_supply_desc psy_desc;
|
| 93 | struct usb_pd_identity partner_ident;
|
| 94 | struct typec_partner_desc partner_desc;
|
| 95 | struct completion req_completion;
|
| 96 | enum power_supply_usb_type usb_type;
|
| 97 | bool attached;
|
| 98 | bool pd_capable;
|
| 99 | bool drswap_support;
|
| 100 | u32 voltage;
|
| 101 | u32 req_voltage;
|
| 102 | u32 max_current;
|
| 103 | u32 op_current;
|
| 104 | u32 spdos[RT1719_MAX_SRCPDO];
|
| 105 | u16 snkcaps[RT1719_MAX_SNKCAP];
|
| 106 | int spdo_num;
|
| 107 | int spdo_sel;
|
| 108 | u32 conn_info;
|
| 109 | u16 conn_stat;
|
| 110 | };
|
| 111 |
|
| 112 | static const enum power_supply_property rt1719_psy_properties[] = {
|
| 113 | POWER_SUPPLY_PROP_ONLINE,
|
| 114 | POWER_SUPPLY_PROP_USB_TYPE,
|
| 115 | POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
| 116 | POWER_SUPPLY_PROP_CURRENT_MAX,
|
| 117 | POWER_SUPPLY_PROP_CURRENT_NOW
|
| 118 | };
|
| 119 |
|
| 120 | static int rt1719_read16(struct rt1719_data *data, unsigned int reg, u16 *val)
|
| 121 | {
|
| 122 | __le16 regval;
|
| 123 | int ret;
|
| 124 |
|
| 125 | ret = regmap_raw_read(data->regmap, reg, ®val, sizeof(regval));
|
| 126 | if (ret)
|
| 127 | return ret;
|
| 128 |
|
| 129 | *val = le16_to_cpu(regval);
|
| 130 | return 0;
|
| 131 | }
|
| 132 |
|
| 133 | static int rt1719_read32(struct rt1719_data *data, unsigned int reg, u32 *val)
|
| 134 | {
|
| 135 | __le32 regval;
|
| 136 | int ret;
|
| 137 |
|
| 138 | ret = regmap_raw_read(data->regmap, reg, ®val, sizeof(regval));
|
| 139 | if (ret)
|
| 140 | return ret;
|
| 141 |
|
| 142 | *val = le32_to_cpu(regval);
|
| 143 | return 0;
|
| 144 | }
|
| 145 |
|
| 146 | static int rt1719_write32(struct rt1719_data *data, unsigned int reg, u32 val)
|
| 147 | {
|
| 148 | __le32 regval = cpu_to_le32(val);
|
| 149 |
|
| 150 | return regmap_raw_write(data->regmap, reg, ®val, sizeof(regval));
|
| 151 | }
|
| 152 |
|
| 153 | static enum typec_pwr_opmode rt1719_get_pwr_opmode(u32 conn, u16 stat)
|
| 154 | {
|
| 155 | u16 cc1, cc2, cc_stat;
|
| 156 |
|
| 157 | cc1 = FIELD_GET(RT1719_CC1_STAT, stat);
|
| 158 | cc2 = FIELD_GET(RT1719_CC2_STAT, stat);
|
| 159 |
|
| 160 | if (conn & RT1719_ATTACH_SNK) {
|
| 161 | if (conn & RT1719_POLARITY_MASK)
|
| 162 | cc_stat = cc2;
|
| 163 | else
|
| 164 | cc_stat = cc1;
|
| 165 |
|
| 166 | switch (cc_stat) {
|
| 167 | case SNK_PWR_3A:
|
| 168 | return TYPEC_PWR_MODE_3_0A;
|
| 169 | case SNK_PWR_1P5A:
|
| 170 | return TYPEC_PWR_MODE_1_5A;
|
| 171 | }
|
| 172 | } else if (conn & RT1719_ATTACH_DBG) {
|
| 173 | if ((cc1 == SNK_PWR_1P5A && cc2 == SNK_PWR_DEF) ||
|
| 174 | (cc1 == SNK_PWR_DEF && cc2 == SNK_PWR_1P5A))
|
| 175 | return TYPEC_PWR_MODE_1_5A;
|
| 176 | else if ((cc1 == SNK_PWR_3A && cc2 == SNK_PWR_DEF) ||
|
| 177 | (cc1 == SNK_PWR_DEF && cc2 == SNK_PWR_3A))
|
| 178 | return TYPEC_PWR_MODE_3_0A;
|
| 179 | }
|
| 180 |
|
| 181 | return TYPEC_PWR_MODE_USB;
|
| 182 | }
|
| 183 |
|
| 184 | static enum typec_data_role rt1719_get_data_role(u32 conn)
|
| 185 | {
|
| 186 | if (conn & RT1719_DATAROLE_MASK)
|
| 187 | return TYPEC_HOST;
|
| 188 | return TYPEC_DEVICE;
|
| 189 | }
|
| 190 |
|
| 191 | static void rt1719_set_data_role(struct rt1719_data *data,
|
| 192 | enum typec_data_role data_role,
|
| 193 | bool attached)
|
| 194 | {
|
| 195 | enum usb_role usb_role = USB_ROLE_NONE;
|
| 196 |
|
| 197 | if (attached) {
|
| 198 | if (data_role == TYPEC_HOST)
|
| 199 | usb_role = USB_ROLE_HOST;
|
| 200 | else
|
| 201 | usb_role = USB_ROLE_DEVICE;
|
| 202 | }
|
| 203 |
|
| 204 | usb_role_switch_set_role(data->role_sw, usb_role);
|
| 205 | typec_set_data_role(data->port, data_role);
|
| 206 | }
|
| 207 |
|
| 208 | static void rt1719_update_data_role(struct rt1719_data *data)
|
| 209 | {
|
| 210 | if (!data->attached)
|
| 211 | return;
|
| 212 |
|
| 213 | rt1719_set_data_role(data, rt1719_get_data_role(data->conn_info), true);
|
| 214 | }
|
| 215 |
|
| 216 | static void rt1719_register_partner(struct rt1719_data *data)
|
| 217 | {
|
| 218 | u16 spec_rev = 0;
|
| 219 |
|
| 220 | if (data->pd_capable) {
|
| 221 | u32 rev;
|
| 222 |
|
| 223 | rev = FIELD_GET(RT1719_PDSPECREV_MASK, data->conn_info);
|
| 224 | switch (rev) {
|
| 225 | case USBPD_SPECREV_3_0:
|
| 226 | spec_rev = 0x0300;
|
| 227 | break;
|
| 228 | case USBPD_SPECREV_2_0:
|
| 229 | spec_rev = 0x0200;
|
| 230 | break;
|
| 231 | default:
|
| 232 | spec_rev = 0x0100;
|
| 233 | break;
|
| 234 | }
|
| 235 | }
|
| 236 |
|
| 237 |
|
| 238 | if (data->partner)
|
| 239 | typec_unregister_partner(data->partner);
|
| 240 |
|
| 241 | memset(&data->partner_ident, 0, sizeof(data->partner_ident));
|
| 242 | data->partner_desc.usb_pd = data->pd_capable;
|
| 243 | data->partner_desc.pd_revision = spec_rev;
|
| 244 |
|
| 245 | if (data->conn_info & RT1719_ATTACH_DBG)
|
| 246 | data->partner_desc.accessory = TYPEC_ACCESSORY_DEBUG;
|
| 247 | else
|
| 248 | data->partner_desc.accessory = TYPEC_ACCESSORY_NONE;
|
| 249 |
|
| 250 | data->partner = typec_register_partner(data->port, &data->partner_desc);
|
| 251 | }
|
| 252 |
|
| 253 | static void rt1719_attach(struct rt1719_data *data)
|
| 254 | {
|
| 255 | enum typec_pwr_opmode pwr_opmode;
|
| 256 | enum typec_data_role data_role;
|
| 257 | u32 volt = 5000, curr = 500;
|
| 258 |
|
| 259 | if (!(data->conn_info & RT1719_ATTACHDEV_MASK))
|
| 260 | return;
|
| 261 |
|
| 262 | pwr_opmode = rt1719_get_pwr_opmode(data->conn_info, data->conn_stat);
|
| 263 | data_role = rt1719_get_data_role(data->conn_info);
|
| 264 |
|
| 265 | typec_set_pwr_opmode(data->port, pwr_opmode);
|
| 266 | rt1719_set_data_role(data, data_role, true);
|
| 267 |
|
| 268 | if (data->conn_info & RT1719_ATTACH_SNK)
|
| 269 | rt1719_register_partner(data);
|
| 270 |
|
| 271 | if (pwr_opmode == TYPEC_PWR_MODE_3_0A)
|
| 272 | curr = 3000;
|
| 273 | else if (pwr_opmode == TYPEC_PWR_MODE_1_5A)
|
| 274 | curr = 1500;
|
| 275 |
|
| 276 | data->voltage = volt * 1000;
|
| 277 | data->max_current = data->op_current = curr * 1000;
|
| 278 | data->attached = true;
|
| 279 |
|
| 280 | power_supply_changed(data->psy);
|
| 281 | }
|
| 282 |
|
| 283 | static void rt1719_detach(struct rt1719_data *data)
|
| 284 | {
|
| 285 | if (!data->attached || (data->conn_info & RT1719_ATTACHDEV_MASK))
|
| 286 | return;
|
| 287 |
|
| 288 | typec_unregister_partner(data->partner);
|
| 289 | data->partner = NULL;
|
| 290 |
|
| 291 | typec_set_pwr_opmode(data->port, TYPEC_PWR_MODE_USB);
|
| 292 | rt1719_set_data_role(data, TYPEC_DEVICE, false);
|
| 293 |
|
| 294 | memset32(data->spdos, 0, RT1719_MAX_SRCPDO);
|
| 295 | data->spdo_num = 0;
|
| 296 | data->voltage = data->max_current = data->op_current = 0;
|
| 297 | data->attached = data->pd_capable = false;
|
| 298 |
|
| 299 | data->usb_type = POWER_SUPPLY_USB_TYPE_C;
|
| 300 |
|
| 301 | power_supply_changed(data->psy);
|
| 302 | }
|
| 303 |
|
| 304 | static void rt1719_update_operating_status(struct rt1719_data *data)
|
| 305 | {
|
| 306 | enum power_supply_usb_type usb_type = POWER_SUPPLY_USB_TYPE_PD;
|
| 307 | u32 voltage, max_current, op_current;
|
| 308 | int i, snk_sel;
|
| 309 |
|
| 310 | for (i = 0; i < data->spdo_num; i++) {
|
| 311 | u32 pdo = data->spdos[i];
|
| 312 | enum pd_pdo_type type = pdo_type(pdo);
|
| 313 |
|
| 314 | if (type == PDO_TYPE_APDO) {
|
| 315 | usb_type = POWER_SUPPLY_USB_TYPE_PD_PPS;
|
| 316 | break;
|
| 317 | }
|
| 318 | }
|
| 319 |
|
| 320 | data->spdo_sel = FIELD_GET(RT1719_SPDOSEL_MASK, data->conn_info);
|
| 321 | if (data->spdo_sel <= 0)
|
| 322 | return;
|
| 323 |
|
| 324 | data->usb_type = usb_type;
|
| 325 |
|
| 326 | voltage = pdo_fixed_voltage(data->spdos[data->spdo_sel - 1]);
|
| 327 | max_current = pdo_max_current(data->spdos[data->spdo_sel - 1]);
|
| 328 |
|
| 329 | switch (voltage) {
|
| 330 | case 5000:
|
| 331 | snk_sel = RT1719_SNKCAP_5V;
|
| 332 | break;
|
| 333 | case 9000:
|
| 334 | snk_sel = RT1719_SNKCAP_9V;
|
| 335 | break;
|
| 336 | case 12000:
|
| 337 | snk_sel = RT1719_SNKCAP_12V;
|
| 338 | break;
|
| 339 | case 15000:
|
| 340 | snk_sel = RT1719_SNKCAP_15V;
|
| 341 | break;
|
| 342 | case 20000:
|
| 343 | snk_sel = RT1719_SNKCAP_20V;
|
| 344 | break;
|
| 345 | default:
|
| 346 | return;
|
| 347 | }
|
| 348 |
|
| 349 | op_current = min(max_current, pdo_max_current(data->snkcaps[snk_sel]));
|
| 350 |
|
| 351 |
|
| 352 | data->voltage = voltage * 1000;
|
| 353 | data->max_current = max_current * 1000;
|
| 354 | data->op_current = op_current * 1000;
|
| 355 |
|
| 356 | power_supply_changed(data->psy);
|
| 357 | }
|
| 358 |
|
| 359 | static void rt1719_update_pwr_opmode(struct rt1719_data *data)
|
| 360 | {
|
| 361 | if (!data->attached)
|
| 362 | return;
|
| 363 |
|
| 364 | if (!data->pd_capable) {
|
| 365 | data->pd_capable = true;
|
| 366 |
|
| 367 | typec_set_pwr_opmode(data->port, TYPEC_PWR_MODE_PD);
|
| 368 | rt1719_register_partner(data);
|
| 369 | }
|
| 370 |
|
| 371 | rt1719_update_operating_status(data);
|
| 372 | }
|
| 373 |
|
| 374 | static void rt1719_update_source_pdos(struct rt1719_data *data)
|
| 375 | {
|
| 376 | int spdo_num = FIELD_GET(RT1719_SPDONUM_MASK, data->conn_info);
|
| 377 | __le32 src_pdos[RT1719_MAX_SRCPDO] = { };
|
| 378 | int i, ret;
|
| 379 |
|
| 380 | if (!data->attached)
|
| 381 | return;
|
| 382 |
|
| 383 | ret = regmap_raw_read(data->regmap, RT1719_REG_SRCPDO1, src_pdos,
|
| 384 | sizeof(__le32) * spdo_num);
|
| 385 | if (ret)
|
| 386 | return;
|
| 387 |
|
| 388 | data->spdo_num = spdo_num;
|
| 389 | for (i = 0; i < spdo_num; i++)
|
| 390 | data->spdos[i] = le32_to_cpu(src_pdos[i]);
|
| 391 | }
|
| 392 |
|
| 393 | static int rt1719_dr_set(struct typec_port *port, enum typec_data_role role)
|
| 394 | {
|
| 395 | struct rt1719_data *data = typec_get_drvdata(port);
|
| 396 | enum typec_data_role cur_role;
|
| 397 | int ret;
|
| 398 |
|
| 399 | if (!data->attached || !data->pd_capable || !data->drswap_support)
|
| 400 | return -EOPNOTSUPP;
|
| 401 |
|
| 402 | if (data->spdo_num > 0 && !(data->spdos[0] & PDO_FIXED_DATA_SWAP))
|
| 403 | return -EINVAL;
|
| 404 |
|
| 405 | cur_role = rt1719_get_data_role(data->conn_info);
|
| 406 | if (cur_role == role)
|
| 407 | return 0;
|
| 408 |
|
| 409 | ret = regmap_update_bits(data->regmap, RT1719_REG_TXCTRL1,
|
| 410 | RT1719_REQDRSWAP_MASK, RT1719_REQDRSWAP_MASK);
|
| 411 | if (ret)
|
| 412 | return ret;
|
| 413 |
|
| 414 | reinit_completion(&data->req_completion);
|
| 415 | ret = wait_for_completion_timeout(&data->req_completion,
|
| 416 | msecs_to_jiffies(400));
|
| 417 | if (ret == 0)
|
| 418 | return -ETIMEDOUT;
|
| 419 |
|
| 420 | cur_role = rt1719_get_data_role(data->conn_info);
|
| 421 | if (cur_role != role)
|
| 422 | return -EAGAIN;
|
| 423 |
|
| 424 | rt1719_set_data_role(data, role, true);
|
| 425 | return 0;
|
| 426 | }
|
| 427 |
|
| 428 | static const struct typec_operations rt1719_port_ops = {
|
| 429 | .dr_set = rt1719_dr_set,
|
| 430 | };
|
| 431 |
|
| 432 | static int rt1719_usbpd_request_voltage(struct rt1719_data *data)
|
| 433 | {
|
| 434 | u32 src_voltage;
|
| 435 | int snk_sel, src_sel = -1;
|
| 436 | int i, ret;
|
| 437 |
|
| 438 | if (!data->attached || !data->pd_capable || data->spdo_sel <= 0)
|
| 439 | return -EINVAL;
|
| 440 |
|
| 441 | src_voltage = pdo_fixed_voltage(data->spdos[data->spdo_sel - 1]);
|
| 442 | if (src_voltage == data->req_voltage)
|
| 443 | return 0;
|
| 444 |
|
| 445 | switch (data->req_voltage) {
|
| 446 | case 5000:
|
| 447 | snk_sel = RT1719_SNKCAP_5V;
|
| 448 | break;
|
| 449 | case 9000:
|
| 450 | snk_sel = RT1719_SNKCAP_9V;
|
| 451 | break;
|
| 452 | case 12000:
|
| 453 | snk_sel = RT1719_SNKCAP_12V;
|
| 454 | break;
|
| 455 | case 15000:
|
| 456 | snk_sel = RT1719_SNKCAP_15V;
|
| 457 | break;
|
| 458 | case 20000:
|
| 459 | snk_sel = RT1719_SNKCAP_20V;
|
| 460 | break;
|
| 461 | default:
|
| 462 | return -EINVAL;
|
| 463 | }
|
| 464 |
|
| 465 | if (!(data->snkcaps[snk_sel] & RT1719_PSEL_SUPPORT))
|
| 466 | return -EINVAL;
|
| 467 |
|
| 468 | for (i = 0; i < data->spdo_num; i++) {
|
| 469 | enum pd_pdo_type type = pdo_type(data->spdos[i]);
|
| 470 |
|
| 471 | if (type != PDO_TYPE_FIXED)
|
| 472 | continue;
|
| 473 |
|
| 474 | src_voltage = pdo_fixed_voltage(data->spdos[i]);
|
| 475 | if (src_voltage == data->req_voltage) {
|
| 476 | src_sel = i;
|
| 477 | break;
|
| 478 | }
|
| 479 | }
|
| 480 |
|
| 481 | if (src_sel == -1)
|
| 482 | return -EOPNOTSUPP;
|
| 483 |
|
| 484 | ret = regmap_update_bits(data->regmap, RT1719_REG_TXCTRL1,
|
| 485 | RT1719_EVALMODE_MASK | RT1719_REQSRCPDO_MASK,
|
| 486 | RT1719_EVALMODE_MASK | (src_sel + 1));
|
| 487 | ret |= regmap_update_bits(data->regmap, RT1719_REG_TXCTRL2,
|
| 488 | RT1719_TXSPDOREQ_MASK, RT1719_TXSPDOREQ_MASK);
|
| 489 | if (ret)
|
| 490 | return ret;
|
| 491 |
|
| 492 | reinit_completion(&data->req_completion);
|
| 493 | ret = wait_for_completion_timeout(&data->req_completion,
|
| 494 | msecs_to_jiffies(400));
|
| 495 | if (!ret)
|
| 496 | return -ETIMEDOUT;
|
| 497 |
|
| 498 | return 0;
|
| 499 | }
|
| 500 |
|
| 501 | static int rt1719_psy_set_property(struct power_supply *psy,
|
| 502 | enum power_supply_property psp,
|
| 503 | const union power_supply_propval *val)
|
| 504 | {
|
| 505 | struct rt1719_data *data = power_supply_get_drvdata(psy);
|
| 506 |
|
| 507 | if (psp == POWER_SUPPLY_PROP_VOLTAGE_NOW) {
|
| 508 | data->req_voltage = val->intval / 1000;
|
| 509 | return rt1719_usbpd_request_voltage(data);
|
| 510 | }
|
| 511 |
|
| 512 | return -EINVAL;
|
| 513 | }
|
| 514 |
|
| 515 | static int rt1719_psy_get_property(struct power_supply *psy,
|
| 516 | enum power_supply_property psp,
|
| 517 | union power_supply_propval *val)
|
| 518 | {
|
| 519 | struct rt1719_data *data = power_supply_get_drvdata(psy);
|
| 520 | int ret = 0;
|
| 521 |
|
| 522 | switch (psp) {
|
| 523 | case POWER_SUPPLY_PROP_ONLINE:
|
| 524 | val->intval = data->attached ? 1 : 0;
|
| 525 | break;
|
| 526 | case POWER_SUPPLY_PROP_USB_TYPE:
|
| 527 | val->intval = data->usb_type;
|
| 528 | break;
|
| 529 | case POWER_SUPPLY_PROP_VOLTAGE_NOW:
|
| 530 | val->intval = data->voltage;
|
| 531 | break;
|
| 532 | case POWER_SUPPLY_PROP_CURRENT_MAX:
|
| 533 | val->intval = data->max_current;
|
| 534 | break;
|
| 535 | case POWER_SUPPLY_PROP_CURRENT_NOW:
|
| 536 | val->intval = data->op_current;
|
| 537 | break;
|
| 538 | default:
|
| 539 | ret = -EINVAL;
|
| 540 | break;
|
| 541 | }
|
| 542 |
|
| 543 | return ret;
|
| 544 | }
|
| 545 |
|
| 546 | static int rt1719_psy_property_is_writeable(struct power_supply *psy,
|
| 547 | enum power_supply_property psp)
|
| 548 | {
|
| 549 | if (psp == POWER_SUPPLY_PROP_VOLTAGE_NOW)
|
| 550 | return 1;
|
| 551 | return 0;
|
| 552 | }
|
| 553 |
|
| 554 | static int devm_rt1719_psy_register(struct rt1719_data *data)
|
| 555 | {
|
| 556 | struct power_supply_config psy_cfg = { };
|
| 557 | char *psy_name;
|
| 558 |
|
| 559 | psy_cfg.fwnode = dev_fwnode(data->dev);
|
| 560 | psy_cfg.drv_data = data;
|
| 561 |
|
| 562 | psy_name = devm_kasprintf(data->dev, GFP_KERNEL, "rt1719-source-psy-%s",
|
| 563 | dev_name(data->dev));
|
| 564 | if (!psy_name)
|
| 565 | return -ENOMEM;
|
| 566 |
|
| 567 | data->psy_desc.name = psy_name;
|
| 568 | data->psy_desc.type = POWER_SUPPLY_TYPE_USB;
|
| 569 | data->psy_desc.usb_types = BIT(POWER_SUPPLY_USB_TYPE_C) |
|
| 570 | BIT(POWER_SUPPLY_USB_TYPE_PD) |
|
| 571 | BIT(POWER_SUPPLY_USB_TYPE_PD_PPS);
|
| 572 | data->psy_desc.properties = rt1719_psy_properties;
|
| 573 | data->psy_desc.num_properties = ARRAY_SIZE(rt1719_psy_properties);
|
| 574 | data->psy_desc.get_property = rt1719_psy_get_property;
|
| 575 | data->psy_desc.set_property = rt1719_psy_set_property;
|
| 576 | data->psy_desc.property_is_writeable = rt1719_psy_property_is_writeable;
|
| 577 |
|
| 578 | data->usb_type = POWER_SUPPLY_USB_TYPE_C;
|
| 579 |
|
| 580 | data->psy = devm_power_supply_register(data->dev, &data->psy_desc,
|
| 581 | &psy_cfg);
|
| 582 |
|
| 583 | return PTR_ERR_OR_ZERO(data->psy);
|
| 584 | }
|
| 585 |
|
| 586 | static irqreturn_t rt1719_irq_handler(int irq, void *priv)
|
| 587 | {
|
| 588 | struct rt1719_data *data = priv;
|
| 589 | u32 events, conn_info;
|
| 590 | u16 conn_stat;
|
| 591 | int ret;
|
| 592 |
|
| 593 | ret = rt1719_read32(data, RT1719_REG_EVENTS, &events);
|
| 594 | ret |= rt1719_read32(data, RT1719_REG_POLICYINFO, &conn_info);
|
| 595 | ret |= rt1719_read16(data, RT1719_REG_STATS, &conn_stat);
|
| 596 | if (ret)
|
| 597 | return IRQ_NONE;
|
| 598 |
|
| 599 | data->conn_info = conn_info;
|
| 600 | data->conn_stat = conn_stat;
|
| 601 |
|
| 602 | events &= (RT1719_INT_DRSW_ACCEPT | RT1719_INT_RX_SRCCAP |
|
| 603 | RT1719_INT_VBUS_PRESENT | RT1719_INT_VBUS_DCT |
|
| 604 | RT1719_INT_PE_SNK_RDY);
|
| 605 |
|
| 606 | if (events & RT1719_INT_DRSW_ACCEPT)
|
| 607 | rt1719_update_data_role(data);
|
| 608 |
|
| 609 | if (events & RT1719_INT_VBUS_PRESENT)
|
| 610 | rt1719_attach(data);
|
| 611 |
|
| 612 | if (events & RT1719_INT_VBUS_DCT)
|
| 613 | rt1719_detach(data);
|
| 614 |
|
| 615 | if (events & RT1719_INT_RX_SRCCAP)
|
| 616 | rt1719_update_source_pdos(data);
|
| 617 |
|
| 618 | if (events & RT1719_INT_PE_SNK_RDY) {
|
| 619 | complete(&data->req_completion);
|
| 620 | rt1719_update_pwr_opmode(data);
|
| 621 | }
|
| 622 |
|
| 623 |
|
| 624 | rt1719_write32(data, RT1719_REG_EVENTS, events);
|
| 625 |
|
| 626 | return IRQ_HANDLED;
|
| 627 | }
|
| 628 |
|
| 629 | static int rt1719_irq_init(struct rt1719_data *data)
|
| 630 | {
|
| 631 | struct i2c_client *i2c = to_i2c_client(data->dev);
|
| 632 | u32 irq_enable;
|
| 633 | int ret;
|
| 634 |
|
| 635 | irq_enable = RT1719_INT_DRSW_ACCEPT | RT1719_INT_RX_SRCCAP |
|
| 636 | RT1719_INT_VBUS_DCT | RT1719_INT_VBUS_PRESENT |
|
| 637 | RT1719_INT_PE_SNK_RDY;
|
| 638 |
|
| 639 | ret = rt1719_write32(data, RT1719_REG_MASKS, irq_enable);
|
| 640 | if (ret) {
|
| 641 | dev_err(&i2c->dev, "Failed to config irq enable\n");
|
| 642 | return ret;
|
| 643 | }
|
| 644 |
|
| 645 | return devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL,
|
| 646 | rt1719_irq_handler, IRQF_ONESHOT,
|
| 647 | dev_name(&i2c->dev), data);
|
| 648 | }
|
| 649 |
|
| 650 | static int rt1719_init_attach_state(struct rt1719_data *data)
|
| 651 | {
|
| 652 | u32 conn_info, irq_clear;
|
| 653 | u16 conn_stat;
|
| 654 | int ret;
|
| 655 |
|
| 656 | irq_clear = RT1719_INT_DRSW_ACCEPT | RT1719_INT_RX_SRCCAP |
|
| 657 | RT1719_INT_VBUS_DCT | RT1719_INT_VBUS_PRESENT |
|
| 658 | RT1719_INT_PE_SNK_RDY;
|
| 659 |
|
| 660 | ret = rt1719_read32(data, RT1719_REG_POLICYINFO, &conn_info);
|
| 661 | ret |= rt1719_read16(data, RT1719_REG_STATS, &conn_stat);
|
| 662 | ret |= rt1719_write32(data, RT1719_REG_EVENTS, irq_clear);
|
| 663 | if (ret)
|
| 664 | return ret;
|
| 665 |
|
| 666 | data->conn_info = conn_info;
|
| 667 | data->conn_stat = conn_stat;
|
| 668 |
|
| 669 | if (conn_info & RT1719_ATTACHDEV_MASK)
|
| 670 | rt1719_attach(data);
|
| 671 |
|
| 672 | if (conn_info & RT1719_PE_EXP_CONTRACT) {
|
| 673 | rt1719_update_source_pdos(data);
|
| 674 | rt1719_update_pwr_opmode(data);
|
| 675 | }
|
| 676 |
|
| 677 | return 0;
|
| 678 | }
|
| 679 |
|
| 680 | #define RT1719_PSEL_CAPINFO(_lomask, _milliwatt, _himask, _milliamp) { \
|
| 681 | .lomask = _lomask, \
|
| 682 | .milliwatt = _milliwatt, \
|
| 683 | .himask = _himask, \
|
| 684 | .milliamp = _milliamp, \
|
| 685 | }
|
| 686 |
|
| 687 | static const struct rt1719_psel_cap rt1719_psel_caps[] = {
|
| 688 | RT1719_PSEL_CAPINFO(0x18, 75000, 0x10, 5000),
|
| 689 | RT1719_PSEL_CAPINFO(0x18, 60000, 0x10, 4500),
|
| 690 | RT1719_PSEL_CAPINFO(0x18, 45000, 0x10, 4000),
|
| 691 | RT1719_PSEL_CAPINFO(0x18, 30000, 0x10, 3500),
|
| 692 | RT1719_PSEL_CAPINFO(0x18, 25000, 0x10, 3000),
|
| 693 | RT1719_PSEL_CAPINFO(0x18, 20000, 0x10, 2500),
|
| 694 | RT1719_PSEL_CAPINFO(0x18, 15000, 0x10, 2000),
|
| 695 | RT1719_PSEL_CAPINFO(0x18, 10000, 0x10, 1000),
|
| 696 | RT1719_PSEL_CAPINFO(0x1C, 60000, 0x1F, 5000),
|
| 697 | RT1719_PSEL_CAPINFO(0x1C, 45000, 0x1F, 4500),
|
| 698 | RT1719_PSEL_CAPINFO(0x1C, 30000, 0x1F, 4000),
|
| 699 | RT1719_PSEL_CAPINFO(0x1C, 24000, 0x1F, 3500),
|
| 700 | RT1719_PSEL_CAPINFO(0x1C, 15000, 0x1F, 3000),
|
| 701 | RT1719_PSEL_CAPINFO(0x1C, 10000, 0x1F, 2500),
|
| 702 | RT1719_PSEL_CAPINFO(0x0C, 60000, 0x1F, 2000),
|
| 703 | RT1719_PSEL_CAPINFO(0x0C, 45000, 0x1F, 1000),
|
| 704 | RT1719_PSEL_CAPINFO(0x0C, 36000, 0x08, 5000),
|
| 705 | RT1719_PSEL_CAPINFO(0x0C, 30000, 0x08, 4500),
|
| 706 | RT1719_PSEL_CAPINFO(0x0C, 24000, 0x08, 4000),
|
| 707 | RT1719_PSEL_CAPINFO(0x0C, 15000, 0x08, 3500),
|
| 708 | RT1719_PSEL_CAPINFO(0x0C, 10000, 0x08, 3000),
|
| 709 | RT1719_PSEL_CAPINFO(0x1E, 45000, 0x08, 2500),
|
| 710 | RT1719_PSEL_CAPINFO(0x1E, 36000, 0x08, 2000),
|
| 711 | RT1719_PSEL_CAPINFO(0x1E, 27000, 0x08, 1500),
|
| 712 | RT1719_PSEL_CAPINFO(0x1E, 20000, 0x08, 1000),
|
| 713 | RT1719_PSEL_CAPINFO(0x1E, 15000, 0x0F, 5000),
|
| 714 | RT1719_PSEL_CAPINFO(0x1E, 9000, 0x0F, 4500),
|
| 715 | RT1719_PSEL_CAPINFO(0x0E, 45000, 0x0F, 4000),
|
| 716 | RT1719_PSEL_CAPINFO(0x0E, 36000, 0x0F, 3500),
|
| 717 | RT1719_PSEL_CAPINFO(0x0E, 27000, 0x0F, 3000),
|
| 718 | RT1719_PSEL_CAPINFO(0x0E, 20000, 0x0F, 2500),
|
| 719 | RT1719_PSEL_CAPINFO(0x0E, 15000, 0x0F, 2000),
|
| 720 | RT1719_PSEL_CAPINFO(0x0E, 9000, 0x0F, 1500),
|
| 721 | RT1719_PSEL_CAPINFO(0x06, 45000, 0x0F, 1000),
|
| 722 | RT1719_PSEL_CAPINFO(0x06, 36000, 0x0F, 500),
|
| 723 | RT1719_PSEL_CAPINFO(0x06, 27000, 0x04, 5000),
|
| 724 | RT1719_PSEL_CAPINFO(0x06, 24000, 0x04, 4500),
|
| 725 | RT1719_PSEL_CAPINFO(0x06, 18000, 0x04, 4000),
|
| 726 | RT1719_PSEL_CAPINFO(0x06, 12000, 0x04, 3500),
|
| 727 | RT1719_PSEL_CAPINFO(0x06, 9000, 0x04, 3000),
|
| 728 | RT1719_PSEL_CAPINFO(0x1F, 25000, 0x04, 2500),
|
| 729 | RT1719_PSEL_CAPINFO(0x1F, 20000, 0x04, 2000),
|
| 730 | RT1719_PSEL_CAPINFO(0x1F, 15000, 0x04, 1500),
|
| 731 | RT1719_PSEL_CAPINFO(0x1F, 10000, 0x04, 1000),
|
| 732 | RT1719_PSEL_CAPINFO(0x1F, 7500, 0x07, 5000),
|
| 733 | RT1719_PSEL_CAPINFO(0x0F, 25000, 0x07, 4500),
|
| 734 | RT1719_PSEL_CAPINFO(0x0F, 20000, 0x07, 4000),
|
| 735 | RT1719_PSEL_CAPINFO(0x0F, 15000, 0x07, 3500),
|
| 736 | RT1719_PSEL_CAPINFO(0x0F, 10000, 0x07, 3000),
|
| 737 | RT1719_PSEL_CAPINFO(0x0F, 7500, 0x07, 2500),
|
| 738 | RT1719_PSEL_CAPINFO(0x07, 25000, 0x07, 2000),
|
| 739 | RT1719_PSEL_CAPINFO(0x07, 20000, 0x07, 1500),
|
| 740 | RT1719_PSEL_CAPINFO(0x07, 15000, 0x07, 1000),
|
| 741 | RT1719_PSEL_CAPINFO(0x07, 10000, 0x07, 500),
|
| 742 | RT1719_PSEL_CAPINFO(0x07, 7500, 0x03, 5000),
|
| 743 | RT1719_PSEL_CAPINFO(0x03, 25000, 0x03, 4500),
|
| 744 | RT1719_PSEL_CAPINFO(0x03, 20000, 0x03, 4000),
|
| 745 | RT1719_PSEL_CAPINFO(0x03, 15000, 0x03, 3500),
|
| 746 | RT1719_PSEL_CAPINFO(0x03, 10000, 0x03, 3000),
|
| 747 | RT1719_PSEL_CAPINFO(0x03, 7500, 0x03, 2500),
|
| 748 | RT1719_PSEL_CAPINFO(0x01, 15000, 0x03, 2000),
|
| 749 | RT1719_PSEL_CAPINFO(0x01, 10000, 0x03, 1500),
|
| 750 | RT1719_PSEL_CAPINFO(0x01, 7500, 0x03, 1000),
|
| 751 | RT1719_PSEL_CAPINFO(0x01, 2500, 0x03, 500)
|
| 752 | };
|
| 753 |
|
| 754 | static u16 rt1719_gen_snkcap_by_current(const struct rt1719_psel_cap *psel_cap,
|
| 755 | enum rt1719_snkcap capsel)
|
| 756 | {
|
| 757 | u16 cap = RT1719_PSEL_SUPPORT;
|
| 758 |
|
| 759 | if (!(psel_cap->himask & BIT(capsel)))
|
| 760 | return 0;
|
| 761 |
|
| 762 | cap |= psel_cap->milliamp / 10;
|
| 763 | return cap;
|
| 764 | }
|
| 765 |
|
| 766 | static u16 rt1719_gen_snkcap_by_watt(const struct rt1719_psel_cap *psel_cap,
|
| 767 | enum rt1719_snkcap capsel)
|
| 768 | {
|
| 769 | u32 volt_div[RT1719_MAX_SNKCAP] = { 5, 9, 12, 15, 20 };
|
| 770 | u16 cap = RT1719_PSEL_SUPPORT;
|
| 771 |
|
| 772 | if (!(psel_cap->lomask & BIT(capsel)))
|
| 773 | return 0;
|
| 774 |
|
| 775 | cap |= min(psel_cap->milliwatt / volt_div[capsel], (u32)5000) / 10;
|
| 776 | return cap;
|
| 777 | }
|
| 778 |
|
| 779 | static u16 rt1719_gen_snkcap(unsigned int pselinfo, enum rt1719_snkcap capsel)
|
| 780 | {
|
| 781 | int psel = FIELD_GET(RT1719_LATPSEL_MASK, pselinfo);
|
| 782 | const struct rt1719_psel_cap *psel_cap;
|
| 783 | bool by_current = false;
|
| 784 |
|
| 785 | if (pselinfo & RT1719_TBLSEL_MASK)
|
| 786 | by_current = true;
|
| 787 |
|
| 788 | psel_cap = rt1719_psel_caps + psel;
|
| 789 | if (by_current)
|
| 790 | return rt1719_gen_snkcap_by_current(psel_cap, capsel);
|
| 791 |
|
| 792 | return rt1719_gen_snkcap_by_watt(psel_cap, capsel);
|
| 793 | }
|
| 794 |
|
| 795 | static int rt1719_get_caps(struct rt1719_data *data)
|
| 796 | {
|
| 797 | unsigned int pselinfo, usbinfo;
|
| 798 | int i, ret;
|
| 799 |
|
| 800 | ret = regmap_read(data->regmap, RT1719_REG_PSELINFO, &pselinfo);
|
| 801 | ret |= regmap_read(data->regmap, RT1719_REG_USBSETINFO, &usbinfo);
|
| 802 | if (ret)
|
| 803 | return ret;
|
| 804 |
|
| 805 | for (i = 0; i < RT1719_MAX_SNKCAP; i++)
|
| 806 | data->snkcaps[i] = rt1719_gen_snkcap(pselinfo, i);
|
| 807 |
|
| 808 | usbinfo = FIELD_GET(RT1719_USBINFO_MASK, usbinfo);
|
| 809 | if (usbinfo == RT1719_USB_DFPUFP)
|
| 810 | data->drswap_support = true;
|
| 811 |
|
| 812 | return 0;
|
| 813 | }
|
| 814 |
|
| 815 | static int rt1719_check_exist(struct rt1719_data *data)
|
| 816 | {
|
| 817 | u16 pid;
|
| 818 | int ret;
|
| 819 |
|
| 820 | ret = rt1719_read16(data, RT1719_REG_VENID, &pid);
|
| 821 | if (ret)
|
| 822 | return ret;
|
| 823 |
|
| 824 | if (pid != RT1719_UNIQUE_PID) {
|
| 825 | dev_err(data->dev, "Incorrect PID 0x%04x\n", pid);
|
| 826 | return -ENODEV;
|
| 827 | }
|
| 828 |
|
| 829 | return 0;
|
| 830 | }
|
| 831 |
|
| 832 | static const struct regmap_config rt1719_regmap_config = {
|
| 833 | .reg_bits = 8,
|
| 834 | .val_bits = 8,
|
| 835 | .max_register = 0xff,
|
| 836 | };
|
| 837 |
|
| 838 | static int rt1719_probe(struct i2c_client *i2c)
|
| 839 | {
|
| 840 | struct rt1719_data *data;
|
| 841 | struct fwnode_handle *fwnode;
|
| 842 | struct typec_capability typec_cap = { };
|
| 843 | int ret;
|
| 844 |
|
| 845 | data = devm_kzalloc(&i2c->dev, sizeof(*data), GFP_KERNEL);
|
| 846 | if (!data)
|
| 847 | return -ENOMEM;
|
| 848 |
|
| 849 | data->dev = &i2c->dev;
|
| 850 | init_completion(&data->req_completion);
|
| 851 |
|
| 852 | data->regmap = devm_regmap_init_i2c(i2c, &rt1719_regmap_config);
|
| 853 | if (IS_ERR(data->regmap)) {
|
| 854 | ret = PTR_ERR(data->regmap);
|
| 855 | dev_err(&i2c->dev, "Failed to init regmap (%d)\n", ret);
|
| 856 | return ret;
|
| 857 | }
|
| 858 |
|
| 859 | ret = rt1719_check_exist(data);
|
| 860 | if (ret)
|
| 861 | return ret;
|
| 862 |
|
| 863 | ret = rt1719_get_caps(data);
|
| 864 | if (ret)
|
| 865 | return ret;
|
| 866 |
|
| 867 | fwnode = device_get_named_child_node(&i2c->dev, "connector");
|
| 868 | if (!fwnode)
|
| 869 | return -ENODEV;
|
| 870 |
|
| 871 | data->role_sw = fwnode_usb_role_switch_get(fwnode);
|
| 872 | if (IS_ERR(data->role_sw)) {
|
| 873 | ret = PTR_ERR(data->role_sw);
|
| 874 | dev_err(&i2c->dev, "Failed to get usb role switch (%d)\n", ret);
|
| 875 | goto err_fwnode_put;
|
| 876 | }
|
| 877 |
|
| 878 | ret = devm_rt1719_psy_register(data);
|
| 879 | if (ret) {
|
| 880 | dev_err(&i2c->dev, "Failed to register psy (%d)\n", ret);
|
| 881 | goto err_role_put;
|
| 882 | }
|
| 883 |
|
| 884 | typec_cap.revision = USB_TYPEC_REV_1_2;
|
| 885 | typec_cap.pd_revision = 0x300;
|
| 886 | typec_cap.type = TYPEC_PORT_SNK;
|
| 887 | typec_cap.data = TYPEC_PORT_DRD;
|
| 888 | typec_cap.ops = &rt1719_port_ops;
|
| 889 | typec_cap.fwnode = fwnode;
|
| 890 | typec_cap.driver_data = data;
|
| 891 | typec_cap.accessory[0] = TYPEC_ACCESSORY_DEBUG;
|
| 892 |
|
| 893 | data->partner_desc.identity = &data->partner_ident;
|
| 894 |
|
| 895 | data->port = typec_register_port(&i2c->dev, &typec_cap);
|
| 896 | if (IS_ERR(data->port)) {
|
| 897 | ret = PTR_ERR(data->port);
|
| 898 | dev_err(&i2c->dev, "Failed to register typec port (%d)\n", ret);
|
| 899 | goto err_role_put;
|
| 900 | }
|
| 901 |
|
| 902 | ret = rt1719_init_attach_state(data);
|
| 903 | if (ret) {
|
| 904 | dev_err(&i2c->dev, "Failed to init attach state (%d)\n", ret);
|
| 905 | goto err_role_put;
|
| 906 | }
|
| 907 |
|
| 908 | ret = rt1719_irq_init(data);
|
| 909 | if (ret) {
|
| 910 | dev_err(&i2c->dev, "Failed to init irq\n");
|
| 911 | goto err_role_put;
|
| 912 | }
|
| 913 |
|
| 914 | fwnode_handle_put(fwnode);
|
| 915 |
|
| 916 | i2c_set_clientdata(i2c, data);
|
| 917 |
|
| 918 | return 0;
|
| 919 |
|
| 920 | err_role_put:
|
| 921 | usb_role_switch_put(data->role_sw);
|
| 922 | err_fwnode_put:
|
| 923 | fwnode_handle_put(fwnode);
|
| 924 |
|
| 925 | return ret;
|
| 926 | }
|
| 927 |
|
| 928 | static void rt1719_remove(struct i2c_client *i2c)
|
| 929 | {
|
| 930 | struct rt1719_data *data = i2c_get_clientdata(i2c);
|
| 931 |
|
| 932 | typec_unregister_port(data->port);
|
| 933 | usb_role_switch_put(data->role_sw);
|
| 934 | }
|
| 935 |
|
| 936 | static const struct of_device_id __maybe_unused rt1719_device_table[] = {
|
| 937 | { .compatible = "richtek,rt1719", },
|
| 938 | { }
|
| 939 | };
|
| 940 | MODULE_DEVICE_TABLE(of, rt1719_device_table);
|
| 941 |
|
| 942 | static struct i2c_driver rt1719_driver = {
|
| 943 | .driver = {
|
| 944 | .name = "rt1719",
|
| 945 | .of_match_table = rt1719_device_table,
|
| 946 | },
|
| 947 | .probe = rt1719_probe,
|
| 948 | .remove = rt1719_remove,
|
| 949 | };
|
| 950 | module_i2c_driver(rt1719_driver);
|
| 951 |
|
| 952 | MODULE_AUTHOR("ChiYuan Huang <[email protected]>");
|
| 953 | MODULE_DESCRIPTION("Richtek RT1719 Sink Only USBPD Controller Driver");
|
| 954 | MODULE_LICENSE("GPL v2");
|