Files
linux-nv-oot/drivers/i2c/busses/i2c-nvvrs11.c
Jon Hunter a809f2cfb5 i2c: nvvrs11: Remove header file
The header file for the NVIDIA I2C NVRS11 driver is only used by this
driver and so remove the header and include the necessary definitions in
the driver source. This avoids having to distribute a header file along
with the main source file.

Bug 4008099

Change-Id: I7ff0e426e74810e34e94ee9ffa28923f40485715
Signed-off-by: Jon Hunter <jonathanh@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2893965
(cherry picked from commit 6e467aeef7848ad55b55b176b89c7fd14c34586d)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2894562
Reviewed-by: svc-mobile-coverity <svc-mobile-coverity@nvidia.com>
Reviewed-by: svc-mobile-cert <svc-mobile-cert@nvidia.com>
Reviewed-by: Shubhi Garg <shgarg@nvidia.com>
GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
2023-05-01 23:45:14 -07:00

372 lines
9.7 KiB
C

// SPDX-License-Identifier: GPL-2.0-only
/*
* Voltage Regulator Specification: VRS11 High Current Voltage Regulator
*
* Copyright (C) 2022-2023 NVIDIA CORPORATION. All rights reserved.
*/
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/types.h>
#include <linux/version.h>
#define VOLTAGE_OFFSET 200 // 0.2V
#define VOLTAGE_SCALE 5 // 5mV
/* Vendor ID */
#define NVVRS11_REG_VENDOR_ID 0x00
#define NVVRS11_REG_MODEL_REV 0x01
/* Voltage Output registers */
#define NVVRS11_REG_VOUT_A 0x30
#define NVVRS11_REG_VOUT_B 0x33
/* Current Output registers */
#define NVVRS11_REG_IOUT_A 0x31
#define NVVRS11_REG_IOUT_B 0x34
/* Temperature registers */
#define NVVRS11_REG_TEMP_A 0x32
#define NVVRS11_REG_TEMP_B 0x35
struct nvvrs11_chip {
struct device *dev;
struct regmap *rmap;
struct i2c_client *client;
const char *loopA_rail_name;
const char *loopB_rail_name;
};
static const struct regmap_range nvvrs11_readable_ranges[] = {
regmap_reg_range(NVVRS11_REG_VENDOR_ID, NVVRS11_REG_MODEL_REV),
regmap_reg_range(NVVRS11_REG_VOUT_A, NVVRS11_REG_TEMP_B),
};
static const struct regmap_access_table nvvrs11_readable_table = {
.yes_ranges = nvvrs11_readable_ranges,
.n_yes_ranges = ARRAY_SIZE(nvvrs11_readable_ranges),
};
static const struct regmap_config nvvrs11_regmap_config = {
.name = "nvvrs11",
.reg_bits = 8,
.val_bits = 8,
.max_register = NVVRS11_REG_TEMP_B + 1,
.cache_type = REGCACHE_RBTREE,
.rd_table = &nvvrs11_readable_table,
};
static ssize_t show_loopA_rail_name(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct nvvrs11_chip *nvvrs_chip = dev_get_drvdata(dev);
return sprintf(buf, "%s\n", nvvrs_chip->loopA_rail_name);
}
static ssize_t show_loopA_rail_voltage(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct nvvrs11_chip *nvvrs_chip = dev_get_drvdata(dev);
int voltage_A;
voltage_A = i2c_smbus_read_byte_data(nvvrs_chip->client, NVVRS11_REG_VOUT_A);
if (voltage_A < 0)
return voltage_A;
voltage_A *= VOLTAGE_SCALE;
voltage_A += VOLTAGE_OFFSET;
return sprintf(buf, "%u mV\n", voltage_A);
}
static ssize_t show_loopA_rail_current(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct nvvrs11_chip *nvvrs_chip = dev_get_drvdata(dev);
int current_A;
current_A = i2c_smbus_read_byte_data(nvvrs_chip->client, NVVRS11_REG_IOUT_A);
if (current_A < 0)
return current_A;
return sprintf(buf, "%u A\n", current_A);
}
static ssize_t show_loopA_rail_power(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct nvvrs11_chip *nvvrs_chip = dev_get_drvdata(dev);
unsigned int power;
int voltage_A;
int current_A;
voltage_A = i2c_smbus_read_byte_data(nvvrs_chip->client, NVVRS11_REG_VOUT_A);
if (voltage_A < 0)
return voltage_A;
voltage_A *= VOLTAGE_SCALE;
voltage_A += VOLTAGE_OFFSET;
current_A = i2c_smbus_read_byte_data(nvvrs_chip->client, NVVRS11_REG_IOUT_A);
if (current_A < 0)
return current_A;
power = (voltage_A * current_A)/1000;
return sprintf(buf, "%u W\n", power);
}
static ssize_t show_loopB_rail_name(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct nvvrs11_chip *nvvrs_chip = dev_get_drvdata(dev);
return sprintf(buf, "%s\n", nvvrs_chip->loopB_rail_name);
}
static ssize_t show_loopB_rail_voltage(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct nvvrs11_chip *nvvrs_chip = dev_get_drvdata(dev);
int voltage_B;
voltage_B = i2c_smbus_read_byte_data(nvvrs_chip->client, NVVRS11_REG_VOUT_B);
if (voltage_B < 0)
return voltage_B;
voltage_B *= VOLTAGE_SCALE;
voltage_B += VOLTAGE_OFFSET;
return sprintf(buf, "%u mV\n", voltage_B);
}
static ssize_t show_loopB_rail_current(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct nvvrs11_chip *nvvrs_chip = dev_get_drvdata(dev);
int current_B;
current_B = i2c_smbus_read_byte_data(nvvrs_chip->client, NVVRS11_REG_IOUT_B);
if (current_B < 0)
return current_B;
return sprintf(buf, "%u A\n", current_B);
}
static ssize_t show_loopB_rail_power(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct nvvrs11_chip *nvvrs_chip = dev_get_drvdata(dev);
unsigned int power;
int voltage_B;
int current_B;
voltage_B = i2c_smbus_read_byte_data(nvvrs_chip->client, NVVRS11_REG_VOUT_B);
if (voltage_B < 0)
return voltage_B;
voltage_B *= VOLTAGE_SCALE;
voltage_B += VOLTAGE_OFFSET;
current_B = i2c_smbus_read_byte_data(nvvrs_chip->client, NVVRS11_REG_IOUT_B);
if (current_B < 0)
return current_B;
power = (voltage_B * current_B)/1000;
return sprintf(buf, "%u W\n", power);
}
static DEVICE_ATTR(loopA_rail_name, S_IRUGO, show_loopA_rail_name, NULL);
static DEVICE_ATTR(loopA_rail_voltage, S_IRUGO, show_loopA_rail_voltage, NULL);
static DEVICE_ATTR(loopA_rail_current, S_IRUGO, show_loopA_rail_current, NULL);
static DEVICE_ATTR(loopA_rail_power, S_IRUGO, show_loopA_rail_power, NULL);
static DEVICE_ATTR(loopB_rail_name, S_IRUGO, show_loopB_rail_name, NULL);
static DEVICE_ATTR(loopB_rail_voltage, S_IRUGO, show_loopB_rail_voltage, NULL);
static DEVICE_ATTR(loopB_rail_current, S_IRUGO, show_loopB_rail_current, NULL);
static DEVICE_ATTR(loopB_rail_power, S_IRUGO, show_loopB_rail_power, NULL);
static struct attribute *nvvrs11_attr[] = {
&dev_attr_loopA_rail_name.attr,
&dev_attr_loopA_rail_voltage.attr,
&dev_attr_loopA_rail_current.attr,
&dev_attr_loopA_rail_power.attr,
&dev_attr_loopB_rail_name.attr,
&dev_attr_loopB_rail_voltage.attr,
&dev_attr_loopB_rail_current.attr,
&dev_attr_loopB_rail_power.attr,
NULL
};
static const struct attribute_group nvvrs11_attr_group = {
.attrs = nvvrs11_attr,
};
static int nvvrs11_create_sys_files(struct device *dev)
{
return sysfs_create_group(&dev->kobj, &nvvrs11_attr_group);
}
static void nvvrs11_delete_sys_files(struct device *dev)
{
return sysfs_remove_group(&dev->kobj, &nvvrs11_attr_group);
}
static int nvvrs11_vendor_info(struct nvvrs11_chip *chip)
{
struct i2c_client *client = chip->client;
int vendor_id, model_rev;
vendor_id = i2c_smbus_read_byte_data(client, NVVRS11_REG_VENDOR_ID);
if (vendor_id < 0) {
dev_err(chip->dev, "Failed to read Vendor ID: %d\n", vendor_id);
return -EINVAL;
}
dev_info(chip->dev, "NVVRS11 Vendor ID: 0x%X \n", vendor_id);
model_rev = i2c_smbus_read_byte_data(client, NVVRS11_REG_MODEL_REV);
if (model_rev < 0) {
dev_err(chip->dev, "Failed to read Model Rev: %d\n", model_rev);
return -EINVAL;
}
dev_info(chip->dev, "NVVRS11 Model Rev: 0x%X\n", model_rev);
return 0;
}
#if KERNEL_VERSION(6, 3, 0) <= LINUX_VERSION_CODE
static int nvvrs11_probe(struct i2c_client *client)
#else
static int nvvrs11_probe(struct i2c_client *client,
const struct i2c_device_id *id)
#endif
{
const struct regmap_config *rmap_config;
struct nvvrs11_chip *nvvrs_chip;
struct device *dev = &client->dev;
struct device_node *np = dev->of_node;
int ret;
nvvrs_chip = devm_kzalloc(&client->dev, sizeof(*nvvrs_chip), GFP_KERNEL);
if (!nvvrs_chip)
return -ENOMEM;
/* Set PEC flag for SMBUS transfer with PEC enabled */
client->flags |= I2C_CLIENT_PEC;
i2c_set_clientdata(client, nvvrs_chip);
nvvrs_chip->client = client;
nvvrs_chip->dev = &client->dev;
rmap_config = &nvvrs11_regmap_config;
nvvrs_chip->rmap = devm_regmap_init_i2c(client, rmap_config);
if (IS_ERR(nvvrs_chip->rmap)) {
ret = PTR_ERR(nvvrs_chip->rmap);
dev_err(nvvrs_chip->dev, "Failed to initialise regmap: %d\n", ret);
return ret;
}
/* Read device tree node info */
nvvrs_chip->loopA_rail_name = of_get_property(np, "rail-name-loopA", NULL);
if (!(nvvrs_chip->loopA_rail_name)) {
dev_info(nvvrs_chip->dev, "loopA rail does not exist\n");
nvvrs_chip->loopA_rail_name = "LoopA";
}
nvvrs_chip->loopB_rail_name = of_get_property(np, "rail-name-loopB", NULL);
if (!(nvvrs_chip->loopB_rail_name)) {
dev_info(nvvrs_chip->dev, "loopB rail does not exist\n");
nvvrs_chip->loopB_rail_name = "LoopB";
}
ret = nvvrs11_create_sys_files(nvvrs_chip->dev);
if (ret) {
dev_err(nvvrs_chip->dev, "Failed to add sysfs entries: %d\n", ret);
return ret;
}
ret = nvvrs11_vendor_info(nvvrs_chip);
if (ret < 0) {
dev_err(nvvrs_chip->dev, "Failed to read vendor info: %d\n", ret);
goto exit;
}
dev_info(nvvrs_chip->dev, "NVVRS11 probe successful");
return 0;
exit:
nvvrs11_delete_sys_files(nvvrs_chip->dev);
dev_info(nvvrs_chip->dev, "NVVRS11 probe failed");
return ret;
}
#if KERNEL_VERSION(6, 1, 0) <= LINUX_VERSION_CODE
static void nvvrs11_remove(struct i2c_client *client)
{
nvvrs11_delete_sys_files(&client->dev);
}
#else
static int nvvrs11_remove(struct i2c_client *client)
{
nvvrs11_delete_sys_files(&client->dev);
return 0;
}
#endif
#ifdef CONFIG_PM_SLEEP
static int nvvrs11_i2c_suspend(struct device *dev)
{
return 0;
}
static int nvvrs11_i2c_resume(struct device *dev)
{
return 0;
}
#endif
static const struct dev_pm_ops nvvrs11_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(nvvrs11_i2c_suspend, nvvrs11_i2c_resume)
};
static const struct of_device_id nvvrs_dt_match[] = {
{ .compatible = "nvidia,vrs11" },
{}
};
MODULE_DEVICE_TABLE(of, nvvrs_dt_match);
static struct i2c_driver nvvrs11_driver = {
.driver = {
.name = "nvvrs11",
.pm = &nvvrs11_pm_ops,
.of_match_table = of_match_ptr(nvvrs_dt_match),
},
.probe = nvvrs11_probe,
.remove = nvvrs11_remove,
};
static int __init nvvrs11_init(void)
{
return i2c_add_driver(&nvvrs11_driver);
}
module_init(nvvrs11_init);
static void __exit nvvrs11_exit(void)
{
i2c_del_driver(&nvvrs11_driver);
}
module_exit(nvvrs11_exit);
MODULE_DESCRIPTION("Nvidia VRS11: High Current Voltage Regulator Spec");
MODULE_AUTHOR("Shubhi Garg <shgarg@nvidia.com>");
MODULE_ALIAS("i2c:nvvrs11");
MODULE_LICENSE("GPL v2");