1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include <linux/acpi.h>
21#include <linux/i2c.h>
22#include <linux/interrupt.h>
23#include <linux/module.h>
24#include <linux/pci.h>
25#include <linux/platform_device.h>
26#include <linux/regulator/consumer.h>
27#include <linux/slab.h>
28#include <linux/usb/pd.h>
29
30#define EXPECTED_PTYPE 4
31
32enum {
33 INT33FE_NODE_FUSB302,
34 INT33FE_NODE_MAX17047,
35 INT33FE_NODE_PI3USB30532,
36 INT33FE_NODE_DISPLAYPORT,
37 INT33FE_NODE_ROLE_SWITCH,
38 INT33FE_NODE_USB_CONNECTOR,
39 INT33FE_NODE_MAX,
40};
41
42struct cht_int33fe_data {
43 struct i2c_client *max17047;
44 struct i2c_client *fusb302;
45 struct i2c_client *pi3usb30532;
46
47 struct fwnode_handle *dp;
48 struct fwnode_handle *mux;
49};
50
51static const struct software_node nodes[];
52
53static const struct software_node_ref_args pi3usb30532_ref = {
54 &nodes[INT33FE_NODE_PI3USB30532]
55};
56
57static const struct software_node_ref_args dp_ref = {
58 &nodes[INT33FE_NODE_DISPLAYPORT]
59};
60
61static struct software_node_ref_args mux_ref;
62
63static const struct software_node_reference usb_connector_refs[] = {
64 { "orientation-switch", 1, &pi3usb30532_ref},
65 { "mode-switch", 1, &pi3usb30532_ref},
66 { "displayport", 1, &dp_ref},
67 { }
68};
69
70static const struct software_node_reference fusb302_refs[] = {
71 { "usb-role-switch", 1, &mux_ref},
72 { }
73};
74
75
76
77
78
79
80
81
82
83static int cht_int33fe_check_for_max17047(struct device *dev, void *data)
84{
85 struct i2c_client **max17047 = data;
86 struct acpi_device *adev;
87 const char *hid;
88
89 adev = ACPI_COMPANION(dev);
90 if (!adev)
91 return 0;
92
93 hid = acpi_device_hid(adev);
94
95
96 if (strcmp(hid, "MAX17047"))
97 return 0;
98
99 *max17047 = to_i2c_client(dev);
100 return 1;
101}
102
103static const char * const max17047_suppliers[] = { "bq24190-charger" };
104
105static const struct property_entry max17047_props[] = {
106 PROPERTY_ENTRY_STRING_ARRAY("supplied-from", max17047_suppliers),
107 { }
108};
109
110static const struct property_entry fusb302_props[] = {
111 PROPERTY_ENTRY_STRING("linux,extcon-name", "cht_wcove_pwrsrc"),
112 { }
113};
114
115#define PDO_FIXED_FLAGS \
116 (PDO_FIXED_DUAL_ROLE | PDO_FIXED_DATA_SWAP | PDO_FIXED_USB_COMM)
117
118static const u32 src_pdo[] = {
119 PDO_FIXED(5000, 1500, PDO_FIXED_FLAGS),
120};
121
122static const u32 snk_pdo[] = {
123 PDO_FIXED(5000, 400, PDO_FIXED_FLAGS),
124 PDO_VAR(5000, 12000, 3000),
125};
126
127static const struct property_entry usb_connector_props[] = {
128 PROPERTY_ENTRY_STRING("data-role", "dual"),
129 PROPERTY_ENTRY_STRING("power-role", "dual"),
130 PROPERTY_ENTRY_STRING("try-power-role", "sink"),
131 PROPERTY_ENTRY_U32_ARRAY("source-pdos", src_pdo),
132 PROPERTY_ENTRY_U32_ARRAY("sink-pdos", snk_pdo),
133 PROPERTY_ENTRY_U32("op-sink-microwatt", 2500000),
134 { }
135};
136
137static const struct software_node nodes[] = {
138 { "fusb302", NULL, fusb302_props, fusb302_refs },
139 { "max17047", NULL, max17047_props },
140 { "pi3usb30532" },
141 { "displayport" },
142 { "usb-role-switch" },
143 { "connector", &nodes[0], usb_connector_props, usb_connector_refs },
144 { }
145};
146
147static int cht_int33fe_setup_mux(struct cht_int33fe_data *data)
148{
149 struct fwnode_handle *fwnode;
150 struct device *dev;
151 struct device *p;
152
153 fwnode = software_node_fwnode(&nodes[INT33FE_NODE_ROLE_SWITCH]);
154 if (!fwnode)
155 return -ENODEV;
156
157
158 p = bus_find_device_by_name(&platform_bus_type, NULL,
159 "intel_xhci_usb_sw");
160 if (!p)
161 return -EPROBE_DEFER;
162
163
164 dev = device_find_child_by_name(p, "intel_xhci_usb_sw-role-switch");
165 put_device(p);
166 if (!dev)
167 return -EPROBE_DEFER;
168
169
170 if (dev->fwnode)
171 fwnode_remove_software_node(fwnode);
172 else
173 dev->fwnode = fwnode;
174
175 data->mux = fwnode_handle_get(dev->fwnode);
176 put_device(dev);
177 mux_ref.node = to_software_node(data->mux);
178
179 return 0;
180}
181
182static int cht_int33fe_setup_dp(struct cht_int33fe_data *data)
183{
184 struct fwnode_handle *fwnode;
185 struct pci_dev *pdev;
186
187 fwnode = software_node_fwnode(&nodes[INT33FE_NODE_DISPLAYPORT]);
188 if (!fwnode)
189 return -ENODEV;
190
191
192 pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, NULL);
193 if (!pdev || pdev->vendor != PCI_VENDOR_ID_INTEL) {
194 pci_dev_put(pdev);
195 return -ENODEV;
196 }
197
198
199 data->dp = device_get_named_child_node(&pdev->dev, "DD02");
200 pci_dev_put(pdev);
201 if (!data->dp)
202 return -ENODEV;
203
204 fwnode->secondary = ERR_PTR(-ENODEV);
205 data->dp->secondary = fwnode;
206
207 return 0;
208}
209
210static void cht_int33fe_remove_nodes(struct cht_int33fe_data *data)
211{
212 software_node_unregister_nodes(nodes);
213
214 if (data->mux) {
215 fwnode_handle_put(data->mux);
216 mux_ref.node = NULL;
217 data->mux = NULL;
218 }
219
220 if (data->dp) {
221 data->dp->secondary = NULL;
222 fwnode_handle_put(data->dp);
223 data->dp = NULL;
224 }
225}
226
227static int cht_int33fe_add_nodes(struct cht_int33fe_data *data)
228{
229 int ret;
230
231 ret = software_node_register_nodes(nodes);
232 if (ret)
233 return ret;
234
235
236
237
238
239
240
241
242
243 ret = cht_int33fe_setup_mux(data);
244 if (ret)
245 goto err_remove_nodes;
246
247
248
249
250
251 ret = cht_int33fe_setup_dp(data);
252 if (ret)
253 goto err_remove_nodes;
254
255 return 0;
256
257err_remove_nodes:
258 cht_int33fe_remove_nodes(data);
259
260 return ret;
261}
262
263static int
264cht_int33fe_register_max17047(struct device *dev, struct cht_int33fe_data *data)
265{
266 struct i2c_client *max17047 = NULL;
267 struct i2c_board_info board_info;
268 struct fwnode_handle *fwnode;
269 int ret;
270
271 fwnode = software_node_fwnode(&nodes[INT33FE_NODE_MAX17047]);
272 if (!fwnode)
273 return -ENODEV;
274
275 i2c_for_each_dev(&max17047, cht_int33fe_check_for_max17047);
276 if (max17047) {
277
278 fwnode->secondary = ERR_PTR(-ENODEV);
279 max17047->dev.fwnode->secondary = fwnode;
280
281 ret = device_reprobe(&max17047->dev);
282 if (ret)
283 dev_warn(dev, "Reprobing max17047 error: %d\n", ret);
284 return 0;
285 }
286
287 memset(&board_info, 0, sizeof(board_info));
288 strlcpy(board_info.type, "max17047", I2C_NAME_SIZE);
289 board_info.dev_name = "max17047";
290 board_info.fwnode = fwnode;
291 data->max17047 = i2c_acpi_new_device(dev, 1, &board_info);
292
293 return PTR_ERR_OR_ZERO(data->max17047);
294}
295
296static int cht_int33fe_probe(struct platform_device *pdev)
297{
298 struct device *dev = &pdev->dev;
299 struct i2c_board_info board_info;
300 struct cht_int33fe_data *data;
301 struct fwnode_handle *fwnode;
302 struct regulator *regulator;
303 unsigned long long ptyp;
304 acpi_status status;
305 int fusb302_irq;
306 int ret;
307
308 status = acpi_evaluate_integer(ACPI_HANDLE(dev), "PTYP", NULL, &ptyp);
309 if (ACPI_FAILURE(status)) {
310 dev_err(dev, "Error getting PTYPE\n");
311 return -ENODEV;
312 }
313
314
315
316
317
318 if (ptyp != EXPECTED_PTYPE)
319 return -ENODEV;
320
321
322 if (!acpi_dev_present("INT34D3", "1", 3)) {
323 dev_err(dev, "Error PTYPE == %d, but no INT34D3 device\n",
324 EXPECTED_PTYPE);
325 return -ENODEV;
326 }
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342 regulator = regulator_get_optional(dev, "cht_wc_usb_typec_vbus");
343 if (IS_ERR(regulator)) {
344 ret = PTR_ERR(regulator);
345 return (ret == -ENODEV) ? -EPROBE_DEFER : ret;
346 }
347 regulator_put(regulator);
348
349
350 fusb302_irq = acpi_dev_gpio_irq_get(ACPI_COMPANION(dev), 1);
351 if (fusb302_irq < 0) {
352 if (fusb302_irq != -EPROBE_DEFER)
353 dev_err(dev, "Error getting FUSB302 irq\n");
354 return fusb302_irq;
355 }
356
357 data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
358 if (!data)
359 return -ENOMEM;
360
361 ret = cht_int33fe_add_nodes(data);
362 if (ret)
363 return ret;
364
365
366 ret = cht_int33fe_register_max17047(dev, data);
367 if (ret)
368 goto out_remove_nodes;
369
370 fwnode = software_node_fwnode(&nodes[INT33FE_NODE_FUSB302]);
371 if (!fwnode) {
372 ret = -ENODEV;
373 goto out_unregister_max17047;
374 }
375
376 memset(&board_info, 0, sizeof(board_info));
377 strlcpy(board_info.type, "typec_fusb302", I2C_NAME_SIZE);
378 board_info.dev_name = "fusb302";
379 board_info.fwnode = fwnode;
380 board_info.irq = fusb302_irq;
381
382 data->fusb302 = i2c_acpi_new_device(dev, 2, &board_info);
383 if (IS_ERR(data->fusb302)) {
384 ret = PTR_ERR(data->fusb302);
385 goto out_unregister_max17047;
386 }
387
388 fwnode = software_node_fwnode(&nodes[INT33FE_NODE_PI3USB30532]);
389 if (!fwnode) {
390 ret = -ENODEV;
391 goto out_unregister_fusb302;
392 }
393
394 memset(&board_info, 0, sizeof(board_info));
395 board_info.dev_name = "pi3usb30532";
396 board_info.fwnode = fwnode;
397 strlcpy(board_info.type, "pi3usb30532", I2C_NAME_SIZE);
398
399 data->pi3usb30532 = i2c_acpi_new_device(dev, 3, &board_info);
400 if (IS_ERR(data->pi3usb30532)) {
401 ret = PTR_ERR(data->pi3usb30532);
402 goto out_unregister_fusb302;
403 }
404
405 platform_set_drvdata(pdev, data);
406
407 return 0;
408
409out_unregister_fusb302:
410 i2c_unregister_device(data->fusb302);
411
412out_unregister_max17047:
413 i2c_unregister_device(data->max17047);
414
415out_remove_nodes:
416 cht_int33fe_remove_nodes(data);
417
418 return ret;
419}
420
421static int cht_int33fe_remove(struct platform_device *pdev)
422{
423 struct cht_int33fe_data *data = platform_get_drvdata(pdev);
424
425 i2c_unregister_device(data->pi3usb30532);
426 i2c_unregister_device(data->fusb302);
427 i2c_unregister_device(data->max17047);
428
429 cht_int33fe_remove_nodes(data);
430
431 return 0;
432}
433
434static const struct acpi_device_id cht_int33fe_acpi_ids[] = {
435 { "INT33FE", },
436 { }
437};
438MODULE_DEVICE_TABLE(acpi, cht_int33fe_acpi_ids);
439
440static struct platform_driver cht_int33fe_driver = {
441 .driver = {
442 .name = "Intel Cherry Trail ACPI INT33FE driver",
443 .acpi_match_table = ACPI_PTR(cht_int33fe_acpi_ids),
444 },
445 .probe = cht_int33fe_probe,
446 .remove = cht_int33fe_remove,
447};
448
449module_platform_driver(cht_int33fe_driver);
450
451MODULE_DESCRIPTION("Intel Cherry Trail ACPI INT33FE pseudo device driver");
452MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
453MODULE_LICENSE("GPL v2");
454