1 // SPDX-License-Identifier: GPL-2.0-only
3 * ChromeOS Device Tree Hardware Prober
5 * Copyright (c) 2024 Google LLC
8 #include <linux/array_size.h>
9 #include <linux/errno.h>
10 #include <linux/i2c-of-prober.h>
11 #include <linux/module.h>
13 #include <linux/platform_device.h>
14 #include <linux/stddef.h>
16 #define DRV_NAME "chromeos_of_hw_prober"
19 * struct hw_prober_entry - Holds an entry for the hardware prober
21 * @compatible: compatible string to match against the machine
22 * @prober: prober function to call when machine matches
23 * @data: extra data for the prober function
25 struct hw_prober_entry
{
26 const char *compatible
;
27 int (*prober
)(struct device
*dev
, const void *data
);
31 struct chromeos_i2c_probe_data
{
32 const struct i2c_of_probe_cfg
*cfg
;
33 const struct i2c_of_probe_simple_opts
*opts
;
36 static int chromeos_i2c_component_prober(struct device
*dev
, const void *_data
)
38 const struct chromeos_i2c_probe_data
*data
= _data
;
39 struct i2c_of_probe_simple_ctx ctx
= {
43 return i2c_of_probe_component(dev
, data
->cfg
, &ctx
);
46 #define DEFINE_CHROMEOS_I2C_PROBE_CFG_SIMPLE_BY_TYPE(_type) \
47 static const struct i2c_of_probe_cfg chromeos_i2c_probe_simple_ ## _type ## _cfg = { \
49 .ops = &i2c_of_probe_simple_ops, \
52 #define DEFINE_CHROMEOS_I2C_PROBE_DATA_DUMB_BY_TYPE(_type) \
53 static const struct chromeos_i2c_probe_data chromeos_i2c_probe_dumb_ ## _type = { \
54 .cfg = &(const struct i2c_of_probe_cfg) { \
59 DEFINE_CHROMEOS_I2C_PROBE_DATA_DUMB_BY_TYPE(touchscreen
);
61 DEFINE_CHROMEOS_I2C_PROBE_CFG_SIMPLE_BY_TYPE(trackpad
);
63 static const struct chromeos_i2c_probe_data chromeos_i2c_probe_hana_trackpad
= {
64 .cfg
= &chromeos_i2c_probe_simple_trackpad_cfg
,
65 .opts
= &(const struct i2c_of_probe_simple_opts
) {
66 .res_node_compatible
= "elan,ekth3000",
69 * ELAN trackpad needs 2 ms for H/W init and 100 ms for F/W init.
70 * Synaptics trackpad needs 100 ms.
71 * However, the regulator is set to "always-on", presumably to
72 * avoid this delay. The ELAN driver is also missing delays.
74 .post_power_on_delay_ms
= 0,
78 static const struct hw_prober_entry hw_prober_platforms
[] = {
80 .compatible
= "google,hana",
81 .prober
= chromeos_i2c_component_prober
,
82 .data
= &chromeos_i2c_probe_dumb_touchscreen
,
84 .compatible
= "google,hana",
85 .prober
= chromeos_i2c_component_prober
,
86 .data
= &chromeos_i2c_probe_hana_trackpad
,
90 static int chromeos_of_hw_prober_probe(struct platform_device
*pdev
)
92 for (size_t i
= 0; i
< ARRAY_SIZE(hw_prober_platforms
); i
++) {
95 if (!of_machine_is_compatible(hw_prober_platforms
[i
].compatible
))
98 ret
= hw_prober_platforms
[i
].prober(&pdev
->dev
, hw_prober_platforms
[i
].data
);
99 /* Ignore unrecoverable errors and keep going through other probers */
100 if (ret
== -EPROBE_DEFER
)
107 static struct platform_driver chromeos_of_hw_prober_driver
= {
108 .probe
= chromeos_of_hw_prober_probe
,
114 static struct platform_device
*chromeos_of_hw_prober_pdev
;
116 static int chromeos_of_hw_prober_driver_init(void)
121 for (i
= 0; i
< ARRAY_SIZE(hw_prober_platforms
); i
++)
122 if (of_machine_is_compatible(hw_prober_platforms
[i
].compatible
))
124 if (i
== ARRAY_SIZE(hw_prober_platforms
))
127 ret
= platform_driver_register(&chromeos_of_hw_prober_driver
);
131 chromeos_of_hw_prober_pdev
=
132 platform_device_register_simple(DRV_NAME
, PLATFORM_DEVID_NONE
, NULL
, 0);
133 if (IS_ERR(chromeos_of_hw_prober_pdev
))
139 platform_driver_unregister(&chromeos_of_hw_prober_driver
);
141 return PTR_ERR(chromeos_of_hw_prober_pdev
);
143 module_init(chromeos_of_hw_prober_driver_init
);
145 static void chromeos_of_hw_prober_driver_exit(void)
147 platform_device_unregister(chromeos_of_hw_prober_pdev
);
148 platform_driver_unregister(&chromeos_of_hw_prober_driver
);
150 module_exit(chromeos_of_hw_prober_driver_exit
);
152 MODULE_LICENSE("GPL");
153 MODULE_DESCRIPTION("ChromeOS device tree hardware prober");
154 MODULE_IMPORT_NS("I2C_OF_PROBER");