18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2011-2016 Synaptics Incorporated 48c2ecf20Sopenharmony_ci * Copyright (c) 2011 Unixphere 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <linux/kernel.h> 88c2ecf20Sopenharmony_ci#include <linux/device.h> 98c2ecf20Sopenharmony_ci#include <linux/irq.h> 108c2ecf20Sopenharmony_ci#include <linux/irqdomain.h> 118c2ecf20Sopenharmony_ci#include <linux/list.h> 128c2ecf20Sopenharmony_ci#include <linux/pm.h> 138c2ecf20Sopenharmony_ci#include <linux/rmi.h> 148c2ecf20Sopenharmony_ci#include <linux/slab.h> 158c2ecf20Sopenharmony_ci#include <linux/types.h> 168c2ecf20Sopenharmony_ci#include <linux/of.h> 178c2ecf20Sopenharmony_ci#include "rmi_bus.h" 188c2ecf20Sopenharmony_ci#include "rmi_driver.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic int debug_flags; 218c2ecf20Sopenharmony_cimodule_param(debug_flags, int, 0644); 228c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug_flags, "control debugging information"); 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_civoid rmi_dbg(int flags, struct device *dev, const char *fmt, ...) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci struct va_format vaf; 278c2ecf20Sopenharmony_ci va_list args; 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci if (flags & debug_flags) { 308c2ecf20Sopenharmony_ci va_start(args, fmt); 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci vaf.fmt = fmt; 338c2ecf20Sopenharmony_ci vaf.va = &args; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, dev, "%pV", &vaf); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci va_end(args); 388c2ecf20Sopenharmony_ci } 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rmi_dbg); 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* 438c2ecf20Sopenharmony_ci * RMI Physical devices 448c2ecf20Sopenharmony_ci * 458c2ecf20Sopenharmony_ci * Physical RMI device consists of several functions serving particular 468c2ecf20Sopenharmony_ci * purpose. For example F11 is a 2D touch sensor while F01 is a generic 478c2ecf20Sopenharmony_ci * function present in every RMI device. 488c2ecf20Sopenharmony_ci */ 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic void rmi_release_device(struct device *dev) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci struct rmi_device *rmi_dev = to_rmi_device(dev); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci kfree(rmi_dev); 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic const struct device_type rmi_device_type = { 588c2ecf20Sopenharmony_ci .name = "rmi4_sensor", 598c2ecf20Sopenharmony_ci .release = rmi_release_device, 608c2ecf20Sopenharmony_ci}; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cibool rmi_is_physical_device(struct device *dev) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci return dev->type == &rmi_device_type; 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci/** 688c2ecf20Sopenharmony_ci * rmi_register_transport_device - register a transport device connection 698c2ecf20Sopenharmony_ci * on the RMI bus. Transport drivers provide communication from the devices 708c2ecf20Sopenharmony_ci * on a bus (such as SPI, I2C, and so on) to the RMI4 sensor. 718c2ecf20Sopenharmony_ci * 728c2ecf20Sopenharmony_ci * @xport: the transport device to register 738c2ecf20Sopenharmony_ci */ 748c2ecf20Sopenharmony_ciint rmi_register_transport_device(struct rmi_transport_dev *xport) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci static atomic_t transport_device_count = ATOMIC_INIT(0); 778c2ecf20Sopenharmony_ci struct rmi_device *rmi_dev; 788c2ecf20Sopenharmony_ci int error; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci rmi_dev = kzalloc(sizeof(struct rmi_device), GFP_KERNEL); 818c2ecf20Sopenharmony_ci if (!rmi_dev) 828c2ecf20Sopenharmony_ci return -ENOMEM; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci device_initialize(&rmi_dev->dev); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci rmi_dev->xport = xport; 878c2ecf20Sopenharmony_ci rmi_dev->number = atomic_inc_return(&transport_device_count) - 1; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci dev_set_name(&rmi_dev->dev, "rmi4-%02d", rmi_dev->number); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci rmi_dev->dev.bus = &rmi_bus_type; 928c2ecf20Sopenharmony_ci rmi_dev->dev.type = &rmi_device_type; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci xport->rmi_dev = rmi_dev; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci error = device_add(&rmi_dev->dev); 978c2ecf20Sopenharmony_ci if (error) 988c2ecf20Sopenharmony_ci goto err_put_device; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci rmi_dbg(RMI_DEBUG_CORE, xport->dev, 1018c2ecf20Sopenharmony_ci "%s: Registered %s as %s.\n", __func__, 1028c2ecf20Sopenharmony_ci dev_name(rmi_dev->xport->dev), dev_name(&rmi_dev->dev)); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci return 0; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_cierr_put_device: 1078c2ecf20Sopenharmony_ci put_device(&rmi_dev->dev); 1088c2ecf20Sopenharmony_ci return error; 1098c2ecf20Sopenharmony_ci} 1108c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rmi_register_transport_device); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci/** 1138c2ecf20Sopenharmony_ci * rmi_unregister_transport_device - unregister a transport device connection 1148c2ecf20Sopenharmony_ci * @xport: the transport driver to unregister 1158c2ecf20Sopenharmony_ci * 1168c2ecf20Sopenharmony_ci */ 1178c2ecf20Sopenharmony_civoid rmi_unregister_transport_device(struct rmi_transport_dev *xport) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci struct rmi_device *rmi_dev = xport->rmi_dev; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci device_del(&rmi_dev->dev); 1228c2ecf20Sopenharmony_ci put_device(&rmi_dev->dev); 1238c2ecf20Sopenharmony_ci} 1248c2ecf20Sopenharmony_ciEXPORT_SYMBOL(rmi_unregister_transport_device); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci/* Function specific stuff */ 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic void rmi_release_function(struct device *dev) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci struct rmi_function *fn = to_rmi_function(dev); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci kfree(fn); 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic const struct device_type rmi_function_type = { 1378c2ecf20Sopenharmony_ci .name = "rmi4_function", 1388c2ecf20Sopenharmony_ci .release = rmi_release_function, 1398c2ecf20Sopenharmony_ci}; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cibool rmi_is_function_device(struct device *dev) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci return dev->type == &rmi_function_type; 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic int rmi_function_match(struct device *dev, struct device_driver *drv) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci struct rmi_function_handler *handler = to_rmi_function_handler(drv); 1498c2ecf20Sopenharmony_ci struct rmi_function *fn = to_rmi_function(dev); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci return fn->fd.function_number == handler->func; 1528c2ecf20Sopenharmony_ci} 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci#ifdef CONFIG_OF 1558c2ecf20Sopenharmony_cistatic void rmi_function_of_probe(struct rmi_function *fn) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci char of_name[9]; 1588c2ecf20Sopenharmony_ci struct device_node *node = fn->rmi_dev->xport->dev->of_node; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci snprintf(of_name, sizeof(of_name), "rmi4-f%02x", 1618c2ecf20Sopenharmony_ci fn->fd.function_number); 1628c2ecf20Sopenharmony_ci fn->dev.of_node = of_get_child_by_name(node, of_name); 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci#else 1658c2ecf20Sopenharmony_cistatic inline void rmi_function_of_probe(struct rmi_function *fn) 1668c2ecf20Sopenharmony_ci{} 1678c2ecf20Sopenharmony_ci#endif 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic struct irq_chip rmi_irq_chip = { 1708c2ecf20Sopenharmony_ci .name = "rmi4", 1718c2ecf20Sopenharmony_ci}; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_cistatic int rmi_create_function_irq(struct rmi_function *fn, 1748c2ecf20Sopenharmony_ci struct rmi_function_handler *handler) 1758c2ecf20Sopenharmony_ci{ 1768c2ecf20Sopenharmony_ci struct rmi_driver_data *drvdata = dev_get_drvdata(&fn->rmi_dev->dev); 1778c2ecf20Sopenharmony_ci int i, error; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci for (i = 0; i < fn->num_of_irqs; i++) { 1808c2ecf20Sopenharmony_ci set_bit(fn->irq_pos + i, fn->irq_mask); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci fn->irq[i] = irq_create_mapping(drvdata->irqdomain, 1838c2ecf20Sopenharmony_ci fn->irq_pos + i); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci irq_set_chip_data(fn->irq[i], fn); 1868c2ecf20Sopenharmony_ci irq_set_chip_and_handler(fn->irq[i], &rmi_irq_chip, 1878c2ecf20Sopenharmony_ci handle_simple_irq); 1888c2ecf20Sopenharmony_ci irq_set_nested_thread(fn->irq[i], 1); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci error = devm_request_threaded_irq(&fn->dev, fn->irq[i], NULL, 1918c2ecf20Sopenharmony_ci handler->attention, IRQF_ONESHOT, 1928c2ecf20Sopenharmony_ci dev_name(&fn->dev), fn); 1938c2ecf20Sopenharmony_ci if (error) { 1948c2ecf20Sopenharmony_ci dev_err(&fn->dev, "Error %d registering IRQ\n", error); 1958c2ecf20Sopenharmony_ci return error; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci return 0; 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic int rmi_function_probe(struct device *dev) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci struct rmi_function *fn = to_rmi_function(dev); 2058c2ecf20Sopenharmony_ci struct rmi_function_handler *handler = 2068c2ecf20Sopenharmony_ci to_rmi_function_handler(dev->driver); 2078c2ecf20Sopenharmony_ci int error; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci rmi_function_of_probe(fn); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci if (handler->probe) { 2128c2ecf20Sopenharmony_ci error = handler->probe(fn); 2138c2ecf20Sopenharmony_ci if (error) 2148c2ecf20Sopenharmony_ci return error; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci if (fn->num_of_irqs && handler->attention) { 2188c2ecf20Sopenharmony_ci error = rmi_create_function_irq(fn, handler); 2198c2ecf20Sopenharmony_ci if (error) 2208c2ecf20Sopenharmony_ci return error; 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci return 0; 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic int rmi_function_remove(struct device *dev) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci struct rmi_function *fn = to_rmi_function(dev); 2298c2ecf20Sopenharmony_ci struct rmi_function_handler *handler = 2308c2ecf20Sopenharmony_ci to_rmi_function_handler(dev->driver); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci if (handler->remove) 2338c2ecf20Sopenharmony_ci handler->remove(fn); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci return 0; 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ciint rmi_register_function(struct rmi_function *fn) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci struct rmi_device *rmi_dev = fn->rmi_dev; 2418c2ecf20Sopenharmony_ci int error; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci device_initialize(&fn->dev); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci dev_set_name(&fn->dev, "%s.fn%02x", 2468c2ecf20Sopenharmony_ci dev_name(&rmi_dev->dev), fn->fd.function_number); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci fn->dev.parent = &rmi_dev->dev; 2498c2ecf20Sopenharmony_ci fn->dev.type = &rmi_function_type; 2508c2ecf20Sopenharmony_ci fn->dev.bus = &rmi_bus_type; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci error = device_add(&fn->dev); 2538c2ecf20Sopenharmony_ci if (error) { 2548c2ecf20Sopenharmony_ci dev_err(&rmi_dev->dev, 2558c2ecf20Sopenharmony_ci "Failed device_register function device %s\n", 2568c2ecf20Sopenharmony_ci dev_name(&fn->dev)); 2578c2ecf20Sopenharmony_ci goto err_put_device; 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev, "Registered F%02X.\n", 2618c2ecf20Sopenharmony_ci fn->fd.function_number); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci return 0; 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cierr_put_device: 2668c2ecf20Sopenharmony_ci put_device(&fn->dev); 2678c2ecf20Sopenharmony_ci return error; 2688c2ecf20Sopenharmony_ci} 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_civoid rmi_unregister_function(struct rmi_function *fn) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci int i; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci rmi_dbg(RMI_DEBUG_CORE, &fn->dev, "Unregistering F%02X.\n", 2758c2ecf20Sopenharmony_ci fn->fd.function_number); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci device_del(&fn->dev); 2788c2ecf20Sopenharmony_ci of_node_put(fn->dev.of_node); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci for (i = 0; i < fn->num_of_irqs; i++) 2818c2ecf20Sopenharmony_ci irq_dispose_mapping(fn->irq[i]); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci put_device(&fn->dev); 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci/** 2878c2ecf20Sopenharmony_ci * rmi_register_function_handler - register a handler for an RMI function 2888c2ecf20Sopenharmony_ci * @handler: RMI handler that should be registered. 2898c2ecf20Sopenharmony_ci * @module: pointer to module that implements the handler 2908c2ecf20Sopenharmony_ci * @mod_name: name of the module implementing the handler 2918c2ecf20Sopenharmony_ci * 2928c2ecf20Sopenharmony_ci * This function performs additional setup of RMI function handler and 2938c2ecf20Sopenharmony_ci * registers it with the RMI core so that it can be bound to 2948c2ecf20Sopenharmony_ci * RMI function devices. 2958c2ecf20Sopenharmony_ci */ 2968c2ecf20Sopenharmony_ciint __rmi_register_function_handler(struct rmi_function_handler *handler, 2978c2ecf20Sopenharmony_ci struct module *owner, 2988c2ecf20Sopenharmony_ci const char *mod_name) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci struct device_driver *driver = &handler->driver; 3018c2ecf20Sopenharmony_ci int error; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci driver->bus = &rmi_bus_type; 3048c2ecf20Sopenharmony_ci driver->owner = owner; 3058c2ecf20Sopenharmony_ci driver->mod_name = mod_name; 3068c2ecf20Sopenharmony_ci driver->probe = rmi_function_probe; 3078c2ecf20Sopenharmony_ci driver->remove = rmi_function_remove; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci error = driver_register(driver); 3108c2ecf20Sopenharmony_ci if (error) { 3118c2ecf20Sopenharmony_ci pr_err("driver_register() failed for %s, error: %d\n", 3128c2ecf20Sopenharmony_ci driver->name, error); 3138c2ecf20Sopenharmony_ci return error; 3148c2ecf20Sopenharmony_ci } 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci return 0; 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__rmi_register_function_handler); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci/** 3218c2ecf20Sopenharmony_ci * rmi_unregister_function_handler - unregister given RMI function handler 3228c2ecf20Sopenharmony_ci * @handler: RMI handler that should be unregistered. 3238c2ecf20Sopenharmony_ci * 3248c2ecf20Sopenharmony_ci * This function unregisters given function handler from RMI core which 3258c2ecf20Sopenharmony_ci * causes it to be unbound from the function devices. 3268c2ecf20Sopenharmony_ci */ 3278c2ecf20Sopenharmony_civoid rmi_unregister_function_handler(struct rmi_function_handler *handler) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci driver_unregister(&handler->driver); 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rmi_unregister_function_handler); 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci/* Bus specific stuff */ 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_cistatic int rmi_bus_match(struct device *dev, struct device_driver *drv) 3368c2ecf20Sopenharmony_ci{ 3378c2ecf20Sopenharmony_ci bool physical = rmi_is_physical_device(dev); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci /* First see if types are not compatible */ 3408c2ecf20Sopenharmony_ci if (physical != rmi_is_physical_driver(drv)) 3418c2ecf20Sopenharmony_ci return 0; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci return physical || rmi_function_match(dev, drv); 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cistruct bus_type rmi_bus_type = { 3478c2ecf20Sopenharmony_ci .match = rmi_bus_match, 3488c2ecf20Sopenharmony_ci .name = "rmi4", 3498c2ecf20Sopenharmony_ci}; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_cistatic struct rmi_function_handler *fn_handlers[] = { 3528c2ecf20Sopenharmony_ci &rmi_f01_handler, 3538c2ecf20Sopenharmony_ci#ifdef CONFIG_RMI4_F03 3548c2ecf20Sopenharmony_ci &rmi_f03_handler, 3558c2ecf20Sopenharmony_ci#endif 3568c2ecf20Sopenharmony_ci#ifdef CONFIG_RMI4_F11 3578c2ecf20Sopenharmony_ci &rmi_f11_handler, 3588c2ecf20Sopenharmony_ci#endif 3598c2ecf20Sopenharmony_ci#ifdef CONFIG_RMI4_F12 3608c2ecf20Sopenharmony_ci &rmi_f12_handler, 3618c2ecf20Sopenharmony_ci#endif 3628c2ecf20Sopenharmony_ci#ifdef CONFIG_RMI4_F30 3638c2ecf20Sopenharmony_ci &rmi_f30_handler, 3648c2ecf20Sopenharmony_ci#endif 3658c2ecf20Sopenharmony_ci#ifdef CONFIG_RMI4_F34 3668c2ecf20Sopenharmony_ci &rmi_f34_handler, 3678c2ecf20Sopenharmony_ci#endif 3688c2ecf20Sopenharmony_ci#ifdef CONFIG_RMI4_F3A 3698c2ecf20Sopenharmony_ci &rmi_f3a_handler, 3708c2ecf20Sopenharmony_ci#endif 3718c2ecf20Sopenharmony_ci#ifdef CONFIG_RMI4_F54 3728c2ecf20Sopenharmony_ci &rmi_f54_handler, 3738c2ecf20Sopenharmony_ci#endif 3748c2ecf20Sopenharmony_ci#ifdef CONFIG_RMI4_F55 3758c2ecf20Sopenharmony_ci &rmi_f55_handler, 3768c2ecf20Sopenharmony_ci#endif 3778c2ecf20Sopenharmony_ci}; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cistatic void __rmi_unregister_function_handlers(int start_idx) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci int i; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci for (i = start_idx; i >= 0; i--) 3848c2ecf20Sopenharmony_ci rmi_unregister_function_handler(fn_handlers[i]); 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic void rmi_unregister_function_handlers(void) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci __rmi_unregister_function_handlers(ARRAY_SIZE(fn_handlers) - 1); 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_cistatic int rmi_register_function_handlers(void) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci int ret; 3958c2ecf20Sopenharmony_ci int i; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(fn_handlers); i++) { 3988c2ecf20Sopenharmony_ci ret = rmi_register_function_handler(fn_handlers[i]); 3998c2ecf20Sopenharmony_ci if (ret) { 4008c2ecf20Sopenharmony_ci pr_err("%s: error registering the RMI F%02x handler: %d\n", 4018c2ecf20Sopenharmony_ci __func__, fn_handlers[i]->func, ret); 4028c2ecf20Sopenharmony_ci goto err_unregister_function_handlers; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci } 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci return 0; 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_cierr_unregister_function_handlers: 4098c2ecf20Sopenharmony_ci __rmi_unregister_function_handlers(i - 1); 4108c2ecf20Sopenharmony_ci return ret; 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ciint rmi_of_property_read_u32(struct device *dev, u32 *result, 4148c2ecf20Sopenharmony_ci const char *prop, bool optional) 4158c2ecf20Sopenharmony_ci{ 4168c2ecf20Sopenharmony_ci int retval; 4178c2ecf20Sopenharmony_ci u32 val = 0; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci retval = of_property_read_u32(dev->of_node, prop, &val); 4208c2ecf20Sopenharmony_ci if (retval && (!optional && retval == -EINVAL)) { 4218c2ecf20Sopenharmony_ci dev_err(dev, "Failed to get %s value: %d\n", 4228c2ecf20Sopenharmony_ci prop, retval); 4238c2ecf20Sopenharmony_ci return retval; 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci *result = val; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci return 0; 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(rmi_of_property_read_u32); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_cistatic int __init rmi_bus_init(void) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci int error; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci error = bus_register(&rmi_bus_type); 4368c2ecf20Sopenharmony_ci if (error) { 4378c2ecf20Sopenharmony_ci pr_err("%s: error registering the RMI bus: %d\n", 4388c2ecf20Sopenharmony_ci __func__, error); 4398c2ecf20Sopenharmony_ci return error; 4408c2ecf20Sopenharmony_ci } 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci error = rmi_register_function_handlers(); 4438c2ecf20Sopenharmony_ci if (error) 4448c2ecf20Sopenharmony_ci goto err_unregister_bus; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci error = rmi_register_physical_driver(); 4478c2ecf20Sopenharmony_ci if (error) { 4488c2ecf20Sopenharmony_ci pr_err("%s: error registering the RMI physical driver: %d\n", 4498c2ecf20Sopenharmony_ci __func__, error); 4508c2ecf20Sopenharmony_ci goto err_unregister_bus; 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci return 0; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_cierr_unregister_bus: 4568c2ecf20Sopenharmony_ci bus_unregister(&rmi_bus_type); 4578c2ecf20Sopenharmony_ci return error; 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_cimodule_init(rmi_bus_init); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_cistatic void __exit rmi_bus_exit(void) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci /* 4648c2ecf20Sopenharmony_ci * We should only ever get here if all drivers are unloaded, so 4658c2ecf20Sopenharmony_ci * all we have to do at this point is unregister ourselves. 4668c2ecf20Sopenharmony_ci */ 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci rmi_unregister_physical_driver(); 4698c2ecf20Sopenharmony_ci rmi_unregister_function_handlers(); 4708c2ecf20Sopenharmony_ci bus_unregister(&rmi_bus_type); 4718c2ecf20Sopenharmony_ci} 4728c2ecf20Sopenharmony_cimodule_exit(rmi_bus_exit); 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ciMODULE_AUTHOR("Christopher Heiny <cheiny@synaptics.com"); 4758c2ecf20Sopenharmony_ciMODULE_AUTHOR("Andrew Duggan <aduggan@synaptics.com"); 4768c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("RMI bus"); 4778c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 478