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