]> Git Repo - J-linux.git/blob - drivers/platform/chrome/chromeos_of_hw_prober.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / platform / chrome / chromeos_of_hw_prober.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * ChromeOS Device Tree Hardware Prober
4  *
5  * Copyright (c) 2024 Google LLC
6  */
7
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>
15
16 #define DRV_NAME        "chromeos_of_hw_prober"
17
18 /**
19  * struct hw_prober_entry - Holds an entry for the hardware prober
20  *
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
24  */
25 struct hw_prober_entry {
26         const char *compatible;
27         int (*prober)(struct device *dev, const void *data);
28         const void *data;
29 };
30
31 struct chromeos_i2c_probe_data {
32         const struct i2c_of_probe_cfg *cfg;
33         const struct i2c_of_probe_simple_opts *opts;
34 };
35
36 static int chromeos_i2c_component_prober(struct device *dev, const void *_data)
37 {
38         const struct chromeos_i2c_probe_data *data = _data;
39         struct i2c_of_probe_simple_ctx ctx = {
40                 .opts = data->opts,
41         };
42
43         return i2c_of_probe_component(dev, data->cfg, &ctx);
44 }
45
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,                                                \
50         }
51
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                 },                                                                              \
57         }
58
59 DEFINE_CHROMEOS_I2C_PROBE_DATA_DUMB_BY_TYPE(touchscreen);
60
61 DEFINE_CHROMEOS_I2C_PROBE_CFG_SIMPLE_BY_TYPE(trackpad);
62
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",
68                 /*
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.
73                  */
74                 .post_power_on_delay_ms = 0,
75         },
76 };
77
78 static const struct hw_prober_entry hw_prober_platforms[] = {
79         {
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,
87         },
88 };
89
90 static int chromeos_of_hw_prober_probe(struct platform_device *pdev)
91 {
92         for (size_t i = 0; i < ARRAY_SIZE(hw_prober_platforms); i++) {
93                 int ret;
94
95                 if (!of_machine_is_compatible(hw_prober_platforms[i].compatible))
96                         continue;
97
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;
102         }
103
104         return 0;
105 }
106
107 static struct platform_driver chromeos_of_hw_prober_driver = {
108         .probe  = chromeos_of_hw_prober_probe,
109         .driver = {
110                 .name = DRV_NAME,
111         },
112 };
113
114 static struct platform_device *chromeos_of_hw_prober_pdev;
115
116 static int chromeos_of_hw_prober_driver_init(void)
117 {
118         size_t i;
119         int ret;
120
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;
126
127         ret = platform_driver_register(&chromeos_of_hw_prober_driver);
128         if (ret)
129                 return ret;
130
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;
135
136         return 0;
137
138 err:
139         platform_driver_unregister(&chromeos_of_hw_prober_driver);
140
141         return PTR_ERR(chromeos_of_hw_prober_pdev);
142 }
143 module_init(chromeos_of_hw_prober_driver_init);
144
145 static void chromeos_of_hw_prober_driver_exit(void)
146 {
147         platform_device_unregister(chromeos_of_hw_prober_pdev);
148         platform_driver_unregister(&chromeos_of_hw_prober_driver);
149 }
150 module_exit(chromeos_of_hw_prober_driver_exit);
151
152 MODULE_LICENSE("GPL");
153 MODULE_DESCRIPTION("ChromeOS device tree hardware prober");
154 MODULE_IMPORT_NS("I2C_OF_PROBER");
This page took 0.053683 seconds and 4 git commands to generate.