0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020 #include <linux/dmi.h>
0021 #include <linux/i2c.h>
0022 #include <linux/interrupt.h>
0023 #include <linux/pci.h>
0024 #include <linux/platform_device.h>
0025 #include <linux/property.h>
0026 #include <linux/regulator/consumer.h>
0027 #include <linux/slab.h>
0028 #include <linux/usb/pd.h>
0029
0030 struct cht_int33fe_data {
0031 struct i2c_client *battery_fg;
0032 struct i2c_client *fusb302;
0033 struct i2c_client *pi3usb30532;
0034 struct fwnode_handle *dp;
0035 };
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045 static int cht_int33fe_check_for_max17047(struct device *dev, void *data)
0046 {
0047 struct i2c_client **max17047 = data;
0048 struct acpi_device *adev;
0049
0050 adev = ACPI_COMPANION(dev);
0051 if (!adev)
0052 return 0;
0053
0054
0055 if (!acpi_dev_hid_uid_match(adev, "MAX17047", NULL))
0056 return 0;
0057
0058 *max17047 = to_i2c_client(dev);
0059 return 1;
0060 }
0061
0062 static const char * const max17047_suppliers[] = { "bq24190-charger" };
0063
0064 static const struct property_entry max17047_properties[] = {
0065 PROPERTY_ENTRY_STRING_ARRAY("supplied-from", max17047_suppliers),
0066 { }
0067 };
0068
0069 static const struct software_node max17047_node = {
0070 .name = "max17047",
0071 .properties = max17047_properties,
0072 };
0073
0074
0075
0076
0077
0078
0079 static struct software_node_ref_args fusb302_mux_refs[] = {
0080 { .node = NULL },
0081 };
0082
0083 static const struct property_entry fusb302_properties[] = {
0084 PROPERTY_ENTRY_STRING("linux,extcon-name", "cht_wcove_pwrsrc"),
0085 PROPERTY_ENTRY_REF_ARRAY("usb-role-switch", fusb302_mux_refs),
0086 { }
0087 };
0088
0089 static const struct software_node fusb302_node = {
0090 .name = "fusb302",
0091 .properties = fusb302_properties,
0092 };
0093
0094 #define PDO_FIXED_FLAGS \
0095 (PDO_FIXED_DUAL_ROLE | PDO_FIXED_DATA_SWAP | PDO_FIXED_USB_COMM)
0096
0097 static const u32 src_pdo[] = {
0098 PDO_FIXED(5000, 1500, PDO_FIXED_FLAGS),
0099 };
0100
0101 static const u32 snk_pdo[] = {
0102 PDO_FIXED(5000, 400, PDO_FIXED_FLAGS),
0103 PDO_VAR(5000, 12000, 3000),
0104 };
0105
0106 static const struct software_node pi3usb30532_node = {
0107 .name = "pi3usb30532",
0108 };
0109
0110 static const struct software_node displayport_node = {
0111 .name = "displayport",
0112 };
0113
0114 static const struct property_entry usb_connector_properties[] = {
0115 PROPERTY_ENTRY_STRING("data-role", "dual"),
0116 PROPERTY_ENTRY_STRING("power-role", "dual"),
0117 PROPERTY_ENTRY_STRING("try-power-role", "sink"),
0118 PROPERTY_ENTRY_U32_ARRAY("source-pdos", src_pdo),
0119 PROPERTY_ENTRY_U32_ARRAY("sink-pdos", snk_pdo),
0120 PROPERTY_ENTRY_U32("op-sink-microwatt", 2500000),
0121 PROPERTY_ENTRY_REF("orientation-switch", &pi3usb30532_node),
0122 PROPERTY_ENTRY_REF("mode-switch", &pi3usb30532_node),
0123 PROPERTY_ENTRY_REF("displayport", &displayport_node),
0124 { }
0125 };
0126
0127 static const struct software_node usb_connector_node = {
0128 .name = "connector",
0129 .parent = &fusb302_node,
0130 .properties = usb_connector_properties,
0131 };
0132
0133 static const struct software_node altmodes_node = {
0134 .name = "altmodes",
0135 .parent = &usb_connector_node,
0136 };
0137
0138 static const struct property_entry dp_altmode_properties[] = {
0139 PROPERTY_ENTRY_U32("svid", 0xff01),
0140 PROPERTY_ENTRY_U32("vdo", 0x0c0086),
0141 { }
0142 };
0143
0144 static const struct software_node dp_altmode_node = {
0145 .name = "displayport-altmode",
0146 .parent = &altmodes_node,
0147 .properties = dp_altmode_properties,
0148 };
0149
0150 static const struct software_node *node_group[] = {
0151 &fusb302_node,
0152 &max17047_node,
0153 &pi3usb30532_node,
0154 &displayport_node,
0155 &usb_connector_node,
0156 &altmodes_node,
0157 &dp_altmode_node,
0158 NULL
0159 };
0160
0161 static int cht_int33fe_setup_dp(struct cht_int33fe_data *data)
0162 {
0163 struct fwnode_handle *fwnode;
0164 struct pci_dev *pdev;
0165
0166 fwnode = software_node_fwnode(&displayport_node);
0167 if (!fwnode)
0168 return -ENODEV;
0169
0170
0171 pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, NULL);
0172 if (!pdev || pdev->vendor != PCI_VENDOR_ID_INTEL) {
0173 pci_dev_put(pdev);
0174 return -ENODEV;
0175 }
0176
0177
0178 data->dp = device_get_named_child_node(&pdev->dev, "DD04");
0179 pci_dev_put(pdev);
0180 if (!data->dp)
0181 return -ENODEV;
0182
0183 fwnode->secondary = ERR_PTR(-ENODEV);
0184 data->dp->secondary = fwnode;
0185
0186 return 0;
0187 }
0188
0189 static void cht_int33fe_remove_nodes(struct cht_int33fe_data *data)
0190 {
0191 software_node_unregister_node_group(node_group);
0192
0193 if (fusb302_mux_refs[0].node) {
0194 fwnode_handle_put(software_node_fwnode(fusb302_mux_refs[0].node));
0195 fusb302_mux_refs[0].node = NULL;
0196 }
0197
0198 if (data->dp) {
0199 data->dp->secondary = NULL;
0200 fwnode_handle_put(data->dp);
0201 data->dp = NULL;
0202 }
0203 }
0204
0205 static int cht_int33fe_add_nodes(struct cht_int33fe_data *data)
0206 {
0207 const struct software_node *mux_ref_node;
0208 int ret;
0209
0210
0211
0212
0213
0214
0215
0216 mux_ref_node = software_node_find_by_name(NULL, "intel-xhci-usb-sw");
0217 if (!mux_ref_node)
0218 return -EPROBE_DEFER;
0219
0220
0221
0222
0223
0224
0225 fusb302_mux_refs[0].node = mux_ref_node;
0226
0227 ret = software_node_register_node_group(node_group);
0228 if (ret)
0229 return ret;
0230
0231
0232
0233
0234
0235
0236
0237 ret = cht_int33fe_setup_dp(data);
0238 if (ret)
0239 goto err_remove_nodes;
0240
0241 return 0;
0242
0243 err_remove_nodes:
0244 cht_int33fe_remove_nodes(data);
0245
0246 return ret;
0247 }
0248
0249 static int
0250 cht_int33fe_register_max17047(struct device *dev, struct cht_int33fe_data *data)
0251 {
0252 struct i2c_client *max17047 = NULL;
0253 struct i2c_board_info board_info;
0254 struct fwnode_handle *fwnode;
0255 int ret;
0256
0257 fwnode = software_node_fwnode(&max17047_node);
0258 if (!fwnode)
0259 return -ENODEV;
0260
0261 i2c_for_each_dev(&max17047, cht_int33fe_check_for_max17047);
0262 if (max17047) {
0263
0264 set_secondary_fwnode(&max17047->dev, fwnode);
0265
0266 ret = device_reprobe(&max17047->dev);
0267 if (ret)
0268 dev_warn(dev, "Reprobing max17047 error: %d\n", ret);
0269 return 0;
0270 }
0271
0272 memset(&board_info, 0, sizeof(board_info));
0273 strlcpy(board_info.type, "max17047", I2C_NAME_SIZE);
0274 board_info.dev_name = "max17047";
0275 board_info.fwnode = fwnode;
0276 data->battery_fg = i2c_acpi_new_device(dev, 1, &board_info);
0277
0278 return PTR_ERR_OR_ZERO(data->battery_fg);
0279 }
0280
0281 static const struct dmi_system_id cht_int33fe_typec_ids[] = {
0282 {
0283
0284
0285
0286
0287
0288
0289
0290
0291 .matches = {
0292 DMI_EXACT_MATCH(DMI_BOARD_VENDOR, "AMI Corporation"),
0293 DMI_EXACT_MATCH(DMI_BOARD_NAME, "Default string"),
0294 DMI_EXACT_MATCH(DMI_BOARD_SERIAL, "Default string"),
0295 DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "Default string"),
0296 },
0297 },
0298 { }
0299 };
0300 MODULE_DEVICE_TABLE(dmi, cht_int33fe_typec_ids);
0301
0302 static int cht_int33fe_typec_probe(struct platform_device *pdev)
0303 {
0304 struct i2c_board_info board_info;
0305 struct device *dev = &pdev->dev;
0306 struct cht_int33fe_data *data;
0307 struct fwnode_handle *fwnode;
0308 struct regulator *regulator;
0309 int fusb302_irq;
0310 int ret;
0311
0312 if (!dmi_check_system(cht_int33fe_typec_ids))
0313 return -ENODEV;
0314
0315 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
0316 if (!data)
0317 return -ENOMEM;
0318
0319
0320
0321
0322
0323
0324
0325
0326
0327
0328
0329
0330
0331
0332
0333 regulator = regulator_get_optional(dev, "cht_wc_usb_typec_vbus");
0334 if (IS_ERR(regulator)) {
0335 ret = PTR_ERR(regulator);
0336 return (ret == -ENODEV) ? -EPROBE_DEFER : ret;
0337 }
0338 regulator_put(regulator);
0339
0340
0341 fusb302_irq = acpi_dev_gpio_irq_get(ACPI_COMPANION(dev), 1);
0342 if (fusb302_irq < 0) {
0343 if (fusb302_irq != -EPROBE_DEFER)
0344 dev_err(dev, "Error getting FUSB302 irq\n");
0345 return fusb302_irq;
0346 }
0347
0348 ret = cht_int33fe_add_nodes(data);
0349 if (ret)
0350 return ret;
0351
0352
0353 ret = cht_int33fe_register_max17047(dev, data);
0354 if (ret)
0355 goto out_remove_nodes;
0356
0357 fwnode = software_node_fwnode(&fusb302_node);
0358 if (!fwnode) {
0359 ret = -ENODEV;
0360 goto out_unregister_max17047;
0361 }
0362
0363 memset(&board_info, 0, sizeof(board_info));
0364 strlcpy(board_info.type, "typec_fusb302", I2C_NAME_SIZE);
0365 board_info.dev_name = "fusb302";
0366 board_info.fwnode = fwnode;
0367 board_info.irq = fusb302_irq;
0368
0369 data->fusb302 = i2c_acpi_new_device(dev, 2, &board_info);
0370 if (IS_ERR(data->fusb302)) {
0371 ret = PTR_ERR(data->fusb302);
0372 goto out_unregister_max17047;
0373 }
0374
0375 fwnode = software_node_fwnode(&pi3usb30532_node);
0376 if (!fwnode) {
0377 ret = -ENODEV;
0378 goto out_unregister_fusb302;
0379 }
0380
0381 memset(&board_info, 0, sizeof(board_info));
0382 board_info.dev_name = "pi3usb30532";
0383 board_info.fwnode = fwnode;
0384 strlcpy(board_info.type, "pi3usb30532", I2C_NAME_SIZE);
0385
0386 data->pi3usb30532 = i2c_acpi_new_device(dev, 3, &board_info);
0387 if (IS_ERR(data->pi3usb30532)) {
0388 ret = PTR_ERR(data->pi3usb30532);
0389 goto out_unregister_fusb302;
0390 }
0391
0392 platform_set_drvdata(pdev, data);
0393
0394 return 0;
0395
0396 out_unregister_fusb302:
0397 i2c_unregister_device(data->fusb302);
0398
0399 out_unregister_max17047:
0400 i2c_unregister_device(data->battery_fg);
0401
0402 out_remove_nodes:
0403 cht_int33fe_remove_nodes(data);
0404
0405 return ret;
0406 }
0407
0408 static int cht_int33fe_typec_remove(struct platform_device *pdev)
0409 {
0410 struct cht_int33fe_data *data = platform_get_drvdata(pdev);
0411
0412 i2c_unregister_device(data->pi3usb30532);
0413 i2c_unregister_device(data->fusb302);
0414 i2c_unregister_device(data->battery_fg);
0415
0416 cht_int33fe_remove_nodes(data);
0417
0418 return 0;
0419 }
0420
0421 static const struct acpi_device_id cht_int33fe_acpi_ids[] = {
0422 { "INT33FE", },
0423 { }
0424 };
0425
0426 static struct platform_driver cht_int33fe_typec_driver = {
0427 .driver = {
0428 .name = "Intel Cherry Trail ACPI INT33FE Type-C driver",
0429 .acpi_match_table = ACPI_PTR(cht_int33fe_acpi_ids),
0430 },
0431 .probe = cht_int33fe_typec_probe,
0432 .remove = cht_int33fe_typec_remove,
0433 };
0434
0435 module_platform_driver(cht_int33fe_typec_driver);
0436
0437 MODULE_DESCRIPTION("Intel Cherry Trail ACPI INT33FE Type-C pseudo device driver");
0438 MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
0439 MODULE_LICENSE("GPL v2");