File Index
Files and directories
Sign in
FILE

chromeos_of_hw_prober.c

File preview with syntax highlighting.

linux-6.19.14/drivers/platform/chrome/chromeos_of_hw_prober.c 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 */
 25struct hw_prober_entry {
 26	const char *compatible;
 27	int (*prober)(struct device *dev, const void *data);
 28	const void *data;
 29};
 30
 31struct chromeos_i2c_probe_data {
 32	const struct i2c_of_probe_cfg *cfg;
 33	const struct i2c_of_probe_simple_opts *opts;
 34};
 35
 36static 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
 59DEFINE_CHROMEOS_I2C_PROBE_DATA_DUMB_BY_TYPE(touchscreen);
 60DEFINE_CHROMEOS_I2C_PROBE_DATA_DUMB_BY_TYPE(trackpad);
 61
 62DEFINE_CHROMEOS_I2C_PROBE_CFG_SIMPLE_BY_TYPE(touchscreen);
 63DEFINE_CHROMEOS_I2C_PROBE_CFG_SIMPLE_BY_TYPE(trackpad);
 64
 65static const struct chromeos_i2c_probe_data chromeos_i2c_probe_hana_trackpad = {
 66	.cfg = &chromeos_i2c_probe_simple_trackpad_cfg,
 67	.opts = &(const struct i2c_of_probe_simple_opts) {
 68		.res_node_compatible = "elan,ekth3000",
 69		.supply_name = "vcc",
 70		/*
 71		 * ELAN trackpad needs 2 ms for H/W init and 100 ms for F/W init.
 72		 * Synaptics trackpad needs 100 ms.
 73		 * However, the regulator is set to "always-on", presumably to
 74		 * avoid this delay. The ELAN driver is also missing delays.
 75		 */
 76		.post_power_on_delay_ms = 0,
 77	},
 78};
 79
 80static const struct chromeos_i2c_probe_data chromeos_i2c_probe_squirtle_touchscreen = {
 81	.cfg = &chromeos_i2c_probe_simple_touchscreen_cfg,
 82	.opts = &(const struct i2c_of_probe_simple_opts) {
 83		.res_node_compatible = "elan,ekth6a12nay",
 84		.supply_name = "vcc33",
 85		.gpio_name = "reset",
 86		.post_power_on_delay_ms = 10,
 87		.post_gpio_config_delay_ms = 300,
 88	},
 89};
 90
 91static const struct hw_prober_entry hw_prober_platforms[] = {
 92	{
 93		.compatible = "google,hana",
 94		.prober = chromeos_i2c_component_prober,
 95		.data = &chromeos_i2c_probe_dumb_touchscreen,
 96	}, {
 97		.compatible = "google,hana",
 98		.prober = chromeos_i2c_component_prober,
 99		.data = &chromeos_i2c_probe_hana_trackpad,
100	}, {
101		.compatible = "google,spherion",
102		.prober = chromeos_i2c_component_prober,
103		.data = &chromeos_i2c_probe_hana_trackpad,
104	}, {
105		.compatible = "google,squirtle",
106		.prober = chromeos_i2c_component_prober,
107		.data = &chromeos_i2c_probe_dumb_trackpad,
108	}, {
109		.compatible = "google,squirtle",
110		.prober = chromeos_i2c_component_prober,
111		.data = &chromeos_i2c_probe_squirtle_touchscreen,
112	}, {
113		.compatible = "google,steelix",
114		.prober = chromeos_i2c_component_prober,
115		.data = &chromeos_i2c_probe_dumb_trackpad,
116	}, {
117		.compatible = "google,voltorb",
118		.prober = chromeos_i2c_component_prober,
119		.data = &chromeos_i2c_probe_dumb_trackpad,
120	},
121};
122
123static int chromeos_of_hw_prober_probe(struct platform_device *pdev)
124{
125	for (size_t i = 0; i < ARRAY_SIZE(hw_prober_platforms); i++) {
126		int ret;
127
128		if (!of_machine_is_compatible(hw_prober_platforms[i].compatible))
129			continue;
130
131		ret = hw_prober_platforms[i].prober(&pdev->dev, hw_prober_platforms[i].data);
132		/* Ignore unrecoverable errors and keep going through other probers */
133		if (ret == -EPROBE_DEFER)
134			return ret;
135	}
136
137	return 0;
138}
139
140static struct platform_driver chromeos_of_hw_prober_driver = {
141	.probe	= chromeos_of_hw_prober_probe,
142	.driver	= {
143		.name = DRV_NAME,
144	},
145};
146
147static struct platform_device *chromeos_of_hw_prober_pdev;
148
149static int chromeos_of_hw_prober_driver_init(void)
150{
151	size_t i;
152	int ret;
153
154	for (i = 0; i < ARRAY_SIZE(hw_prober_platforms); i++)
155		if (of_machine_is_compatible(hw_prober_platforms[i].compatible))
156			break;
157	if (i == ARRAY_SIZE(hw_prober_platforms))
158		return -ENODEV;
159
160	ret = platform_driver_register(&chromeos_of_hw_prober_driver);
161	if (ret)
162		return ret;
163
164	chromeos_of_hw_prober_pdev =
165			platform_device_register_simple(DRV_NAME, PLATFORM_DEVID_NONE, NULL, 0);
166	if (IS_ERR(chromeos_of_hw_prober_pdev))
167		goto err;
168
169	return 0;
170
171err:
172	platform_driver_unregister(&chromeos_of_hw_prober_driver);
173
174	return PTR_ERR(chromeos_of_hw_prober_pdev);
175}
176module_init(chromeos_of_hw_prober_driver_init);
177
178static void chromeos_of_hw_prober_driver_exit(void)
179{
180	platform_device_unregister(chromeos_of_hw_prober_pdev);
181	platform_driver_unregister(&chromeos_of_hw_prober_driver);
182}
183module_exit(chromeos_of_hw_prober_driver_exit);
184
185MODULE_LICENSE("GPL");
186MODULE_DESCRIPTION("ChromeOS device tree hardware prober");
187MODULE_IMPORT_NS("I2C_OF_PROBER");
~/ Read-only file preview.