Linux 6.14-rc1
[linux-stable.git] / drivers / platform / chrome / chromeos_of_hw_prober.c
blobc6992f5cdc7660a58f1d9075ccfa1ed496e6d197
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * ChromeOS Device Tree Hardware Prober
5 * Copyright (c) 2024 Google LLC
6 */
8 #include <linux/array_size.h>
9 #include <linux/errno.h>
10 #include <linux/i2c-of-prober.h>
11 #include <linux/module.h>
12 #include <linux/of.h>
13 #include <linux/platform_device.h>
14 #include <linux/stddef.h>
16 #define DRV_NAME "chromeos_of_hw_prober"
18 /**
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);
28 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 = {
40 .opts = data->opts,
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 = { \
48 .type = #_type, \
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) { \
55 .type = #_type, \
56 }, \
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",
67 .supply_name = "vcc",
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,
83 }, {
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++) {
93 int ret;
95 if (!of_machine_is_compatible(hw_prober_platforms[i].compatible))
96 continue;
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)
101 return ret;
104 return 0;
107 static struct platform_driver chromeos_of_hw_prober_driver = {
108 .probe = chromeos_of_hw_prober_probe,
109 .driver = {
110 .name = DRV_NAME,
114 static struct platform_device *chromeos_of_hw_prober_pdev;
116 static int chromeos_of_hw_prober_driver_init(void)
118 size_t i;
119 int ret;
121 for (i = 0; i < ARRAY_SIZE(hw_prober_platforms); i++)
122 if (of_machine_is_compatible(hw_prober_platforms[i].compatible))
123 break;
124 if (i == ARRAY_SIZE(hw_prober_platforms))
125 return -ENODEV;
127 ret = platform_driver_register(&chromeos_of_hw_prober_driver);
128 if (ret)
129 return ret;
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))
134 goto err;
136 return 0;
138 err:
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");