Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.14 154 lines 4.2 kB view raw
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); 60 61DEFINE_CHROMEOS_I2C_PROBE_CFG_SIMPLE_BY_TYPE(trackpad); 62 63static 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 78static 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 90static 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 107static struct platform_driver chromeos_of_hw_prober_driver = { 108 .probe = chromeos_of_hw_prober_probe, 109 .driver = { 110 .name = DRV_NAME, 111 }, 112}; 113 114static struct platform_device *chromeos_of_hw_prober_pdev; 115 116static 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 138err: 139 platform_driver_unregister(&chromeos_of_hw_prober_driver); 140 141 return PTR_ERR(chromeos_of_hw_prober_pdev); 142} 143module_init(chromeos_of_hw_prober_driver_init); 144 145static 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} 150module_exit(chromeos_of_hw_prober_driver_exit); 151 152MODULE_LICENSE("GPL"); 153MODULE_DESCRIPTION("ChromeOS device tree hardware prober"); 154MODULE_IMPORT_NS("I2C_OF_PROBER");