306 lines
8.6 KiB
C
306 lines
8.6 KiB
C
|
/* Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
|
||
|
*
|
||
|
* This software is licensed under the terms of the GNU General Public
|
||
|
* License version 2, as published by the Free Software Foundation, and
|
||
|
* may be copied, distributed, and modified under those terms.
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*/
|
||
|
|
||
|
|
||
|
#include <linux/module.h>
|
||
|
#include <linux/nvs.h>
|
||
|
#include <linux/of.h>
|
||
|
#include <linux/string.h>
|
||
|
#include <linux/export.h>
|
||
|
|
||
|
|
||
|
const char * const nvs_float_significances[] = {
|
||
|
"micro",
|
||
|
"nano",
|
||
|
};
|
||
|
EXPORT_SYMBOL_GPL(nvs_float_significances);
|
||
|
|
||
|
/**
|
||
|
* nvs_of_dt - NVS sensor device tree configuration.
|
||
|
* @np: mandatory device node pointer.
|
||
|
* @cfg: sensor's configuration pointer.
|
||
|
* This can be called early with cfg == NULL to determine
|
||
|
* if the device is available based on returned -ENODEV or
|
||
|
* -EINVAL.
|
||
|
* @dev_name: name of sensor device. If this is NULL then the
|
||
|
* sensor configuration's name member is used.
|
||
|
*
|
||
|
* Returns: -EINVAL = np and/or cfg are NULL.
|
||
|
* -ENODEV = if device is not available.
|
||
|
* 0 = no default configuration changes were made.
|
||
|
* >0 = number of default configuration changes made.
|
||
|
* Note this does not include expected device tree
|
||
|
* configuration settings such as matrix and
|
||
|
* calibration. Also not included is whether the
|
||
|
* device was disabled via the NVS mechanism.
|
||
|
*/
|
||
|
int nvs_of_dt(const struct device_node *np, struct sensor_cfg *cfg,
|
||
|
const char *dev_name)
|
||
|
{
|
||
|
s32 s32tmp = 0;
|
||
|
u32 u32tmp = 0;
|
||
|
char str[256];
|
||
|
const char *charp;
|
||
|
int lenp;
|
||
|
unsigned int i;
|
||
|
unsigned int cfg_changes = 0;
|
||
|
|
||
|
if (np == NULL)
|
||
|
return -EINVAL;
|
||
|
|
||
|
if (!of_device_is_available(np))
|
||
|
return -ENODEV;
|
||
|
|
||
|
if (cfg == NULL)
|
||
|
return -EINVAL;
|
||
|
|
||
|
if (dev_name == NULL)
|
||
|
dev_name = cfg->name;
|
||
|
if (snprintf(str, sizeof(str), "%s_disable", dev_name) > 0) {
|
||
|
if (!of_property_read_u32(np, str, (u32 *)&i)) {
|
||
|
if (i)
|
||
|
cfg->snsr_id = -1;
|
||
|
}
|
||
|
}
|
||
|
if (snprintf(str, sizeof(str), "%s_float_significance", dev_name) > 0) {
|
||
|
if (!of_property_read_string((struct device_node *)np,
|
||
|
str, &charp)) {
|
||
|
u32tmp = ARRAY_SIZE(nvs_float_significances);
|
||
|
for (i = 0; i < u32tmp; i++) {
|
||
|
if (!strcasecmp(charp,
|
||
|
nvs_float_significances[i])) {
|
||
|
if (cfg->float_significance != i) {
|
||
|
cfg->float_significance = i;
|
||
|
cfg_changes++;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (snprintf(str, sizeof(str), "%s_flags", dev_name) > 0) {
|
||
|
if (!of_property_read_u32(np, str, &u32tmp)) {
|
||
|
i = cfg->flags & SENSOR_FLAG_READONLY_MASK;
|
||
|
u32tmp &= ~SENSOR_FLAG_READONLY_MASK;
|
||
|
i |= u32tmp;
|
||
|
if (cfg->flags != i) {
|
||
|
cfg->flags = i;
|
||
|
cfg_changes++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (snprintf(str, sizeof(str), "%s_kbuffer_size", dev_name) > 0) {
|
||
|
if (!of_property_read_s32(np, str, &s32tmp)) {
|
||
|
if (cfg->kbuf_sz != s32tmp) {
|
||
|
cfg->kbuf_sz = s32tmp;
|
||
|
cfg_changes++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (snprintf(str, sizeof(str), "%s_max_range_ival", dev_name) > 0) {
|
||
|
if (!of_property_read_s32(np, str, &s32tmp)) {
|
||
|
if (cfg->max_range.ival != s32tmp) {
|
||
|
cfg->max_range.ival = s32tmp;
|
||
|
cfg_changes++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (snprintf(str, sizeof(str), "%s_max_range_fval", dev_name) > 0) {
|
||
|
if (!of_property_read_s32(np, str, &s32tmp)) {
|
||
|
if (cfg->max_range.fval != s32tmp) {
|
||
|
cfg->max_range.fval = s32tmp;
|
||
|
cfg_changes++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (snprintf(str, sizeof(str), "%s_resolution_ival", dev_name) > 0) {
|
||
|
if (!of_property_read_s32(np, str, &s32tmp)) {
|
||
|
if (cfg->resolution.ival != s32tmp) {
|
||
|
cfg->resolution.ival = s32tmp;
|
||
|
cfg_changes++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (snprintf(str, sizeof(str), "%s_resolution_fval", dev_name) > 0) {
|
||
|
if (!of_property_read_s32(np, str, &s32tmp)) {
|
||
|
if (cfg->resolution.fval != s32tmp) {
|
||
|
cfg->resolution.fval = s32tmp;
|
||
|
cfg_changes++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (snprintf(str, sizeof(str), "%s_milliamp_ival", dev_name) > 0) {
|
||
|
if (!of_property_read_s32(np, str, &s32tmp)) {
|
||
|
if (cfg->milliamp.ival != s32tmp) {
|
||
|
cfg->milliamp.ival = s32tmp;
|
||
|
cfg_changes++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (snprintf(str, sizeof(str), "%s_milliamp_fval", dev_name) > 0) {
|
||
|
if (!of_property_read_s32(np, str, &s32tmp)) {
|
||
|
if (cfg->milliamp.fval != s32tmp) {
|
||
|
cfg->milliamp.fval = s32tmp;
|
||
|
cfg_changes++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (snprintf(str, sizeof(str), "%s_delay_us_min", dev_name) > 0) {
|
||
|
if (!of_property_read_s32(np, str, &s32tmp)) {
|
||
|
if (cfg->delay_us_min != s32tmp) {
|
||
|
cfg->delay_us_min = s32tmp;
|
||
|
cfg_changes++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (snprintf(str, sizeof(str), "%s_delay_us_max", dev_name) > 0) {
|
||
|
if (!of_property_read_s32(np, str, &s32tmp)) {
|
||
|
if (cfg->delay_us_max != s32tmp) {
|
||
|
cfg->delay_us_max = s32tmp;
|
||
|
cfg_changes++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (snprintf(str, sizeof(str), "%s_fifo_reserved_event_count", dev_name) > 0) {
|
||
|
if (!of_property_read_u32(np, str, &u32tmp)) {
|
||
|
if (cfg->fifo_rsrv_evnt_cnt != u32tmp) {
|
||
|
cfg->fifo_rsrv_evnt_cnt = u32tmp;
|
||
|
cfg_changes++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (snprintf(str, sizeof(str), "%s_fifo_max_event_count", dev_name) > 0) {
|
||
|
if (!of_property_read_u32(np, str, &u32tmp)) {
|
||
|
if (cfg->fifo_max_evnt_cnt != u32tmp) {
|
||
|
cfg->fifo_max_evnt_cnt = u32tmp;
|
||
|
cfg_changes++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (snprintf(str, sizeof(str), "%s_matrix", dev_name) > 0) {
|
||
|
charp = of_get_property(np, str, &lenp);
|
||
|
if (charp && lenp == sizeof(cfg->matrix))
|
||
|
memcpy(&cfg->matrix, charp, lenp);
|
||
|
}
|
||
|
if (snprintf(str, sizeof(str), "%s_uncalibrated_lo", dev_name) > 0)
|
||
|
of_property_read_s32(np, str, (s32 *)&cfg->uncal_lo);
|
||
|
if (snprintf(str, sizeof(str), "%s_uncalibrated_hi", dev_name) > 0)
|
||
|
of_property_read_s32(np, str, (s32 *)&cfg->uncal_hi);
|
||
|
if (snprintf(str, sizeof(str), "%s_calibrated_lo", dev_name) > 0)
|
||
|
of_property_read_s32(np, str, (s32 *)&cfg->cal_lo);
|
||
|
if (snprintf(str, sizeof(str), "%s_calibrated_hi", dev_name) > 0)
|
||
|
of_property_read_s32(np, str, (s32 *)&cfg->cal_hi);
|
||
|
if (snprintf(str, sizeof(str), "%s_threshold_lo", dev_name) > 0) {
|
||
|
if (!of_property_read_s32(np, str, &s32tmp)) {
|
||
|
if (cfg->thresh_lo != s32tmp) {
|
||
|
cfg->thresh_lo = s32tmp;
|
||
|
cfg_changes++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (snprintf(str, sizeof(str), "%s_threshold_hi", dev_name) > 0) {
|
||
|
if (!of_property_read_s32(np, str, &s32tmp)) {
|
||
|
if (cfg->thresh_hi != s32tmp) {
|
||
|
cfg->thresh_hi = s32tmp;
|
||
|
cfg_changes++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (snprintf(str, sizeof(str), "%s_report_count", dev_name) > 0) {
|
||
|
if (!of_property_read_s32(np, str, &s32tmp)) {
|
||
|
if (cfg->report_n != s32tmp) {
|
||
|
cfg->report_n = s32tmp;
|
||
|
cfg_changes++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (snprintf(str, sizeof(str), "%s_scale_ival", dev_name) > 0) {
|
||
|
if (!of_property_read_s32(np, str, &s32tmp)) {
|
||
|
if (cfg->scale.ival != s32tmp) {
|
||
|
cfg->scale.ival = s32tmp;
|
||
|
cfg_changes++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (snprintf(str, sizeof(str), "%s_scale_fval", dev_name) > 0) {
|
||
|
if (!of_property_read_s32(np, str, &s32tmp)) {
|
||
|
if (cfg->scale.fval != s32tmp) {
|
||
|
cfg->scale.fval = s32tmp;
|
||
|
cfg_changes++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (snprintf(str, sizeof(str), "%s_offset_ival", dev_name) > 0) {
|
||
|
if (!of_property_read_s32(np, str, &s32tmp)) {
|
||
|
if (cfg->offset.ival != s32tmp) {
|
||
|
cfg->offset.ival = s32tmp;
|
||
|
cfg_changes++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (snprintf(str, sizeof(str), "%s_offset_fval", dev_name) > 0) {
|
||
|
if (!of_property_read_s32(np, str, &s32tmp)) {
|
||
|
if (cfg->offset.fval != s32tmp) {
|
||
|
cfg->offset.fval = s32tmp;
|
||
|
cfg_changes++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
for (i = 0; i < cfg->ch_n_max; i++) {
|
||
|
if (snprintf(str, sizeof(str), "%s_scale_ival_ch%u",
|
||
|
dev_name, i) > 0) {
|
||
|
if (!of_property_read_s32(np, str, &s32tmp)) {
|
||
|
if (cfg->scales[i].ival != s32tmp) {
|
||
|
cfg->scales[i].ival = s32tmp;
|
||
|
cfg_changes++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (snprintf(str, sizeof(str), "%s_scale_fval_ch%u",
|
||
|
dev_name, i) > 0) {
|
||
|
if (!of_property_read_s32(np, str, &s32tmp)) {
|
||
|
if (cfg->scales[i].fval != s32tmp) {
|
||
|
cfg->scales[i].fval = s32tmp;
|
||
|
cfg_changes++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (snprintf(str, sizeof(str), "%s_offset_ival_ch%u",
|
||
|
dev_name, i) > 0) {
|
||
|
if (!of_property_read_s32(np, str, &s32tmp)) {
|
||
|
if (cfg->offsets[i].ival != s32tmp) {
|
||
|
cfg->offsets[i].ival = s32tmp;
|
||
|
cfg_changes++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (snprintf(str, sizeof(str), "%s_offset_fval_ch%u",
|
||
|
dev_name, i) > 0) {
|
||
|
if (!of_property_read_s32(np, str, &s32tmp)) {
|
||
|
if (cfg->offsets[i].fval != s32tmp) {
|
||
|
cfg->offsets[i].fval = s32tmp;
|
||
|
cfg_changes++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return cfg_changes;
|
||
|
}
|
||
|
EXPORT_SYMBOL_GPL(nvs_of_dt);
|
||
|
|
||
|
MODULE_LICENSE("GPL v2");
|
||
|
MODULE_DESCRIPTION("NVidia Sensor Open Firmware Device Tree module");
|
||
|
MODULE_AUTHOR("NVIDIA Corporation");
|
||
|
|