Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  MEN 14F021P00 Board Management Controller (BMC) hwmon driver.
0004  *
0005  *  This is the core hwmon driver of the MEN 14F021P00 BMC.
0006  *  The BMC monitors the board voltages which can be access with this
0007  *  driver through sysfs.
0008  *
0009  *  Copyright (C) 2014 MEN Mikro Elektronik Nuernberg GmbH
0010  */
0011 
0012 #include <linux/module.h>
0013 #include <linux/kernel.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/hwmon.h>
0016 #include <linux/hwmon-sysfs.h>
0017 #include <linux/jiffies.h>
0018 #include <linux/slab.h>
0019 #include <linux/i2c.h>
0020 #include <linux/err.h>
0021 
0022 #define DRV_NAME  "menf21bmc_hwmon"
0023 
0024 #define BMC_VOLT_COUNT  5
0025 #define MENF21BMC_V33   0
0026 #define MENF21BMC_V5    1
0027 #define MENF21BMC_V12   2
0028 #define MENF21BMC_V5_SB 3
0029 #define MENF21BMC_VBAT  4
0030 
0031 #define IDX_TO_VOLT_MIN_CMD(idx) (0x40 + idx)
0032 #define IDX_TO_VOLT_MAX_CMD(idx) (0x50 + idx)
0033 #define IDX_TO_VOLT_INP_CMD(idx) (0x60 + idx)
0034 
0035 struct menf21bmc_hwmon {
0036     bool valid;
0037     struct i2c_client *i2c_client;
0038     unsigned long last_update;
0039     int in_val[BMC_VOLT_COUNT];
0040     int in_min[BMC_VOLT_COUNT];
0041     int in_max[BMC_VOLT_COUNT];
0042 };
0043 
0044 static const char *const input_names[] = {
0045     [MENF21BMC_V33]     = "MON_3_3V",
0046     [MENF21BMC_V5]      = "MON_5V",
0047     [MENF21BMC_V12]     = "MON_12V",
0048     [MENF21BMC_V5_SB]   = "5V_STANDBY",
0049     [MENF21BMC_VBAT]    = "VBAT"
0050 };
0051 
0052 static struct menf21bmc_hwmon *menf21bmc_hwmon_update(struct device *dev)
0053 {
0054     int i;
0055     int val;
0056     struct menf21bmc_hwmon *drv_data = dev_get_drvdata(dev);
0057     struct menf21bmc_hwmon *data_ret = drv_data;
0058 
0059     if (time_after(jiffies, drv_data->last_update + HZ)
0060         || !drv_data->valid) {
0061         for (i = 0; i < BMC_VOLT_COUNT; i++) {
0062             val = i2c_smbus_read_word_data(drv_data->i2c_client,
0063                                IDX_TO_VOLT_INP_CMD(i));
0064             if (val < 0) {
0065                 data_ret = ERR_PTR(val);
0066                 goto abort;
0067             }
0068             drv_data->in_val[i] = val;
0069         }
0070         drv_data->last_update = jiffies;
0071         drv_data->valid = true;
0072     }
0073 abort:
0074     return data_ret;
0075 }
0076 
0077 static int menf21bmc_hwmon_get_volt_limits(struct menf21bmc_hwmon *drv_data)
0078 {
0079     int i, val;
0080 
0081     for (i = 0; i < BMC_VOLT_COUNT; i++) {
0082         val = i2c_smbus_read_word_data(drv_data->i2c_client,
0083                            IDX_TO_VOLT_MIN_CMD(i));
0084         if (val < 0)
0085             return val;
0086 
0087         drv_data->in_min[i] = val;
0088 
0089         val = i2c_smbus_read_word_data(drv_data->i2c_client,
0090                            IDX_TO_VOLT_MAX_CMD(i));
0091         if (val < 0)
0092             return val;
0093 
0094         drv_data->in_max[i] = val;
0095     }
0096     return 0;
0097 }
0098 
0099 static ssize_t
0100 label_show(struct device *dev, struct device_attribute *devattr, char *buf)
0101 {
0102     struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
0103 
0104     return sprintf(buf, "%s\n", input_names[attr->index]);
0105 }
0106 
0107 static ssize_t
0108 in_show(struct device *dev, struct device_attribute *devattr, char *buf)
0109 {
0110     struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
0111     struct menf21bmc_hwmon *drv_data = menf21bmc_hwmon_update(dev);
0112 
0113     if (IS_ERR(drv_data))
0114         return PTR_ERR(drv_data);
0115 
0116     return sprintf(buf, "%d\n", drv_data->in_val[attr->index]);
0117 }
0118 
0119 static ssize_t
0120 min_show(struct device *dev, struct device_attribute *devattr, char *buf)
0121 {
0122     struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
0123     struct menf21bmc_hwmon *drv_data = dev_get_drvdata(dev);
0124 
0125     return sprintf(buf, "%d\n", drv_data->in_min[attr->index]);
0126 }
0127 
0128 static ssize_t
0129 max_show(struct device *dev, struct device_attribute *devattr, char *buf)
0130 {
0131     struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
0132     struct menf21bmc_hwmon *drv_data = dev_get_drvdata(dev);
0133 
0134     return sprintf(buf, "%d\n", drv_data->in_max[attr->index]);
0135 }
0136 
0137 static SENSOR_DEVICE_ATTR_RO(in0_input, in, 0);
0138 static SENSOR_DEVICE_ATTR_RO(in0_min, min, 0);
0139 static SENSOR_DEVICE_ATTR_RO(in0_max, max, 0);
0140 static SENSOR_DEVICE_ATTR_RO(in0_label, label, 0);
0141 static SENSOR_DEVICE_ATTR_RO(in1_input, in, 1);
0142 static SENSOR_DEVICE_ATTR_RO(in1_min, min, 1);
0143 static SENSOR_DEVICE_ATTR_RO(in1_max, max, 1);
0144 static SENSOR_DEVICE_ATTR_RO(in1_label, label, 1);
0145 static SENSOR_DEVICE_ATTR_RO(in2_input, in, 2);
0146 static SENSOR_DEVICE_ATTR_RO(in2_min, min, 2);
0147 static SENSOR_DEVICE_ATTR_RO(in2_max, max, 2);
0148 static SENSOR_DEVICE_ATTR_RO(in2_label, label, 2);
0149 static SENSOR_DEVICE_ATTR_RO(in3_input, in, 3);
0150 static SENSOR_DEVICE_ATTR_RO(in3_min, min, 3);
0151 static SENSOR_DEVICE_ATTR_RO(in3_max, max, 3);
0152 static SENSOR_DEVICE_ATTR_RO(in3_label, label, 3);
0153 static SENSOR_DEVICE_ATTR_RO(in4_input, in, 4);
0154 static SENSOR_DEVICE_ATTR_RO(in4_min, min, 4);
0155 static SENSOR_DEVICE_ATTR_RO(in4_max, max, 4);
0156 static SENSOR_DEVICE_ATTR_RO(in4_label, label, 4);
0157 
0158 static struct attribute *menf21bmc_hwmon_attrs[] = {
0159     &sensor_dev_attr_in0_input.dev_attr.attr,
0160     &sensor_dev_attr_in0_min.dev_attr.attr,
0161     &sensor_dev_attr_in0_max.dev_attr.attr,
0162     &sensor_dev_attr_in0_label.dev_attr.attr,
0163 
0164     &sensor_dev_attr_in1_input.dev_attr.attr,
0165     &sensor_dev_attr_in1_min.dev_attr.attr,
0166     &sensor_dev_attr_in1_max.dev_attr.attr,
0167     &sensor_dev_attr_in1_label.dev_attr.attr,
0168 
0169     &sensor_dev_attr_in2_input.dev_attr.attr,
0170     &sensor_dev_attr_in2_min.dev_attr.attr,
0171     &sensor_dev_attr_in2_max.dev_attr.attr,
0172     &sensor_dev_attr_in2_label.dev_attr.attr,
0173 
0174     &sensor_dev_attr_in3_input.dev_attr.attr,
0175     &sensor_dev_attr_in3_min.dev_attr.attr,
0176     &sensor_dev_attr_in3_max.dev_attr.attr,
0177     &sensor_dev_attr_in3_label.dev_attr.attr,
0178 
0179     &sensor_dev_attr_in4_input.dev_attr.attr,
0180     &sensor_dev_attr_in4_min.dev_attr.attr,
0181     &sensor_dev_attr_in4_max.dev_attr.attr,
0182     &sensor_dev_attr_in4_label.dev_attr.attr,
0183     NULL
0184 };
0185 
0186 ATTRIBUTE_GROUPS(menf21bmc_hwmon);
0187 
0188 static int menf21bmc_hwmon_probe(struct platform_device *pdev)
0189 {
0190     int ret;
0191     struct menf21bmc_hwmon *drv_data;
0192     struct i2c_client *i2c_client = to_i2c_client(pdev->dev.parent);
0193     struct device *hwmon_dev;
0194 
0195     drv_data = devm_kzalloc(&pdev->dev, sizeof(struct menf21bmc_hwmon),
0196                 GFP_KERNEL);
0197     if (!drv_data)
0198         return -ENOMEM;
0199 
0200     drv_data->i2c_client = i2c_client;
0201 
0202     ret = menf21bmc_hwmon_get_volt_limits(drv_data);
0203     if (ret) {
0204         dev_err(&pdev->dev, "failed to read sensor limits");
0205         return ret;
0206     }
0207 
0208     hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev,
0209                            "menf21bmc", drv_data,
0210                            menf21bmc_hwmon_groups);
0211     if (IS_ERR(hwmon_dev))
0212         return PTR_ERR(hwmon_dev);
0213 
0214     dev_info(&pdev->dev, "MEN 14F021P00 BMC hwmon device enabled");
0215 
0216     return 0;
0217 }
0218 
0219 static struct platform_driver menf21bmc_hwmon = {
0220     .probe      = menf21bmc_hwmon_probe,
0221     .driver     = {
0222         .name       = DRV_NAME,
0223     },
0224 };
0225 
0226 module_platform_driver(menf21bmc_hwmon);
0227 
0228 MODULE_AUTHOR("Andreas Werner <andreas.werner@men.de>");
0229 MODULE_DESCRIPTION("MEN 14F021P00 BMC hwmon");
0230 MODULE_LICENSE("GPL v2");
0231 MODULE_ALIAS("platform:menf21bmc_hwmon");