18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * i2c-boardinfo.c - collect pre-declarations of I2C devices 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/export.h> 78c2ecf20Sopenharmony_ci#include <linux/i2c.h> 88c2ecf20Sopenharmony_ci#include <linux/kernel.h> 98c2ecf20Sopenharmony_ci#include <linux/property.h> 108c2ecf20Sopenharmony_ci#include <linux/rwsem.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "i2c-core.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci/* These symbols are exported ONLY FOR the i2c core. 178c2ecf20Sopenharmony_ci * No other users will be supported. 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_ciDECLARE_RWSEM(__i2c_board_lock); 208c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__i2c_board_lock); 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ciLIST_HEAD(__i2c_board_list); 238c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__i2c_board_list); 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ciint __i2c_first_dynamic_bus_num; 268c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__i2c_first_dynamic_bus_num); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/** 308c2ecf20Sopenharmony_ci * i2c_register_board_info - statically declare I2C devices 318c2ecf20Sopenharmony_ci * @busnum: identifies the bus to which these devices belong 328c2ecf20Sopenharmony_ci * @info: vector of i2c device descriptors 338c2ecf20Sopenharmony_ci * @len: how many descriptors in the vector; may be zero to reserve 348c2ecf20Sopenharmony_ci * the specified bus number. 358c2ecf20Sopenharmony_ci * 368c2ecf20Sopenharmony_ci * Systems using the Linux I2C driver stack can declare tables of board info 378c2ecf20Sopenharmony_ci * while they initialize. This should be done in board-specific init code 388c2ecf20Sopenharmony_ci * near arch_initcall() time, or equivalent, before any I2C adapter driver is 398c2ecf20Sopenharmony_ci * registered. For example, mainboard init code could define several devices, 408c2ecf20Sopenharmony_ci * as could the init code for each daughtercard in a board stack. 418c2ecf20Sopenharmony_ci * 428c2ecf20Sopenharmony_ci * The I2C devices will be created later, after the adapter for the relevant 438c2ecf20Sopenharmony_ci * bus has been registered. After that moment, standard driver model tools 448c2ecf20Sopenharmony_ci * are used to bind "new style" I2C drivers to the devices. The bus number 458c2ecf20Sopenharmony_ci * for any device declared using this routine is not available for dynamic 468c2ecf20Sopenharmony_ci * allocation. 478c2ecf20Sopenharmony_ci * 488c2ecf20Sopenharmony_ci * The board info passed can safely be __initdata, but be careful of embedded 498c2ecf20Sopenharmony_ci * pointers (for platform_data, functions, etc) since that won't be copied. 508c2ecf20Sopenharmony_ci * Device properties are deep-copied though. 518c2ecf20Sopenharmony_ci */ 528c2ecf20Sopenharmony_ciint i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci int status; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci down_write(&__i2c_board_lock); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci /* dynamic bus numbers will be assigned after the last static one */ 598c2ecf20Sopenharmony_ci if (busnum >= __i2c_first_dynamic_bus_num) 608c2ecf20Sopenharmony_ci __i2c_first_dynamic_bus_num = busnum + 1; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci for (status = 0; len; len--, info++) { 638c2ecf20Sopenharmony_ci struct i2c_devinfo *devinfo; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci devinfo = kzalloc(sizeof(*devinfo), GFP_KERNEL); 668c2ecf20Sopenharmony_ci if (!devinfo) { 678c2ecf20Sopenharmony_ci pr_debug("i2c-core: can't register boardinfo!\n"); 688c2ecf20Sopenharmony_ci status = -ENOMEM; 698c2ecf20Sopenharmony_ci break; 708c2ecf20Sopenharmony_ci } 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci devinfo->busnum = busnum; 738c2ecf20Sopenharmony_ci devinfo->board_info = *info; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci if (info->properties) { 768c2ecf20Sopenharmony_ci devinfo->board_info.properties = 778c2ecf20Sopenharmony_ci property_entries_dup(info->properties); 788c2ecf20Sopenharmony_ci if (IS_ERR(devinfo->board_info.properties)) { 798c2ecf20Sopenharmony_ci status = PTR_ERR(devinfo->board_info.properties); 808c2ecf20Sopenharmony_ci kfree(devinfo); 818c2ecf20Sopenharmony_ci break; 828c2ecf20Sopenharmony_ci } 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if (info->resources) { 868c2ecf20Sopenharmony_ci devinfo->board_info.resources = 878c2ecf20Sopenharmony_ci kmemdup(info->resources, 888c2ecf20Sopenharmony_ci info->num_resources * 898c2ecf20Sopenharmony_ci sizeof(*info->resources), 908c2ecf20Sopenharmony_ci GFP_KERNEL); 918c2ecf20Sopenharmony_ci if (!devinfo->board_info.resources) { 928c2ecf20Sopenharmony_ci status = -ENOMEM; 938c2ecf20Sopenharmony_ci kfree(devinfo); 948c2ecf20Sopenharmony_ci break; 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci list_add_tail(&devinfo->list, &__i2c_board_list); 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci up_write(&__i2c_board_lock); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci return status; 1048c2ecf20Sopenharmony_ci} 105