1 /* 2 * MEN 14F021P00 Board Management Controller (BMC) hwmon driver. 3 * 4 * This is the core hwmon driver of the MEN 14F021P00 BMC. 5 * The BMC monitors the board voltages which can be access with this 6 * driver through sysfs. 7 * 8 * Copyright (C) 2014 MEN Mikro Elektronik Nuernberg GmbH 9 * 10 * This program is free software; you can redistribute it and/or modify it 11 * under the terms of the GNU General Public License as published by the 12 * Free Software Foundation; either version 2 of the License, or (at your 13 * option) any later version. 14 */ 15 16 #include <linux/module.h> 17 #include <linux/kernel.h> 18 #include <linux/platform_device.h> 19 #include <linux/hwmon.h> 20 #include <linux/hwmon-sysfs.h> 21 #include <linux/jiffies.h> 22 #include <linux/slab.h> 23 #include <linux/i2c.h> 24 25 #define DRV_NAME "menf21bmc_hwmon" 26 27 #define BMC_VOLT_COUNT 5 28 #define MENF21BMC_V33 0 29 #define MENF21BMC_V5 1 30 #define MENF21BMC_V12 2 31 #define MENF21BMC_V5_SB 3 32 #define MENF21BMC_VBAT 4 33 34 #define IDX_TO_VOLT_MIN_CMD(idx) (0x40 + idx) 35 #define IDX_TO_VOLT_MAX_CMD(idx) (0x50 + idx) 36 #define IDX_TO_VOLT_INP_CMD(idx) (0x60 + idx) 37 38 struct menf21bmc_hwmon { 39 bool valid; 40 struct i2c_client *i2c_client; 41 unsigned long last_update; 42 int in_val[BMC_VOLT_COUNT]; 43 int in_min[BMC_VOLT_COUNT]; 44 int in_max[BMC_VOLT_COUNT]; 45 }; 46 47 static const char *const input_names[] = { 48 [MENF21BMC_V33] = "MON_3_3V", 49 [MENF21BMC_V5] = "MON_5V", 50 [MENF21BMC_V12] = "MON_12V", 51 [MENF21BMC_V5_SB] = "5V_STANDBY", 52 [MENF21BMC_VBAT] = "VBAT" 53 }; 54 55 static struct menf21bmc_hwmon *menf21bmc_hwmon_update(struct device *dev) 56 { 57 int i; 58 int val; 59 struct menf21bmc_hwmon *drv_data = dev_get_drvdata(dev); 60 struct menf21bmc_hwmon *data_ret = drv_data; 61 62 if (time_after(jiffies, drv_data->last_update + HZ) 63 || !drv_data->valid) { 64 for (i = 0; i < BMC_VOLT_COUNT; i++) { 65 val = i2c_smbus_read_word_data(drv_data->i2c_client, 66 IDX_TO_VOLT_INP_CMD(i)); 67 if (val < 0) { 68 data_ret = ERR_PTR(val); 69 goto abort; 70 } 71 drv_data->in_val[i] = val; 72 } 73 drv_data->last_update = jiffies; 74 drv_data->valid = true; 75 } 76 abort: 77 return data_ret; 78 } 79 80 static int menf21bmc_hwmon_get_volt_limits(struct menf21bmc_hwmon *drv_data) 81 { 82 int i, val; 83 84 for (i = 0; i < BMC_VOLT_COUNT; i++) { 85 val = i2c_smbus_read_word_data(drv_data->i2c_client, 86 IDX_TO_VOLT_MIN_CMD(i)); 87 if (val < 0) 88 return val; 89 90 drv_data->in_min[i] = val; 91 92 val = i2c_smbus_read_word_data(drv_data->i2c_client, 93 IDX_TO_VOLT_MAX_CMD(i)); 94 if (val < 0) 95 return val; 96 97 drv_data->in_max[i] = val; 98 } 99 return 0; 100 } 101 102 static ssize_t 103 show_label(struct device *dev, struct device_attribute *devattr, char *buf) 104 { 105 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 106 107 return sprintf(buf, "%s\n", input_names[attr->index]); 108 } 109 110 static ssize_t 111 show_in(struct device *dev, struct device_attribute *devattr, char *buf) 112 { 113 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 114 struct menf21bmc_hwmon *drv_data = menf21bmc_hwmon_update(dev); 115 116 if (IS_ERR(drv_data)) 117 return PTR_ERR(drv_data); 118 119 return sprintf(buf, "%d\n", drv_data->in_val[attr->index]); 120 } 121 122 static ssize_t 123 show_min(struct device *dev, struct device_attribute *devattr, char *buf) 124 { 125 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 126 struct menf21bmc_hwmon *drv_data = dev_get_drvdata(dev); 127 128 return sprintf(buf, "%d\n", drv_data->in_min[attr->index]); 129 } 130 131 static ssize_t 132 show_max(struct device *dev, struct device_attribute *devattr, char *buf) 133 { 134 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 135 struct menf21bmc_hwmon *drv_data = dev_get_drvdata(dev); 136 137 return sprintf(buf, "%d\n", drv_data->in_max[attr->index]); 138 } 139 140 #define create_voltage_sysfs(idx) \ 141 static SENSOR_DEVICE_ATTR(in##idx##_input, S_IRUGO, \ 142 show_in, NULL, idx); \ 143 static SENSOR_DEVICE_ATTR(in##idx##_min, S_IRUGO, \ 144 show_min, NULL, idx); \ 145 static SENSOR_DEVICE_ATTR(in##idx##_max, S_IRUGO, \ 146 show_max, NULL, idx); \ 147 static SENSOR_DEVICE_ATTR(in##idx##_label, S_IRUGO, \ 148 show_label, NULL, idx); 149 150 create_voltage_sysfs(0); 151 create_voltage_sysfs(1); 152 create_voltage_sysfs(2); 153 create_voltage_sysfs(3); 154 create_voltage_sysfs(4); 155 156 static struct attribute *menf21bmc_hwmon_attrs[] = { 157 &sensor_dev_attr_in0_input.dev_attr.attr, 158 &sensor_dev_attr_in0_min.dev_attr.attr, 159 &sensor_dev_attr_in0_max.dev_attr.attr, 160 &sensor_dev_attr_in0_label.dev_attr.attr, 161 162 &sensor_dev_attr_in1_input.dev_attr.attr, 163 &sensor_dev_attr_in1_min.dev_attr.attr, 164 &sensor_dev_attr_in1_max.dev_attr.attr, 165 &sensor_dev_attr_in1_label.dev_attr.attr, 166 167 &sensor_dev_attr_in2_input.dev_attr.attr, 168 &sensor_dev_attr_in2_min.dev_attr.attr, 169 &sensor_dev_attr_in2_max.dev_attr.attr, 170 &sensor_dev_attr_in2_label.dev_attr.attr, 171 172 &sensor_dev_attr_in3_input.dev_attr.attr, 173 &sensor_dev_attr_in3_min.dev_attr.attr, 174 &sensor_dev_attr_in3_max.dev_attr.attr, 175 &sensor_dev_attr_in3_label.dev_attr.attr, 176 177 &sensor_dev_attr_in4_input.dev_attr.attr, 178 &sensor_dev_attr_in4_min.dev_attr.attr, 179 &sensor_dev_attr_in4_max.dev_attr.attr, 180 &sensor_dev_attr_in4_label.dev_attr.attr, 181 NULL 182 }; 183 184 ATTRIBUTE_GROUPS(menf21bmc_hwmon); 185 186 static int menf21bmc_hwmon_probe(struct platform_device *pdev) 187 { 188 int ret; 189 struct menf21bmc_hwmon *drv_data; 190 struct i2c_client *i2c_client = to_i2c_client(pdev->dev.parent); 191 struct device *hwmon_dev; 192 193 drv_data = devm_kzalloc(&pdev->dev, sizeof(struct menf21bmc_hwmon), 194 GFP_KERNEL); 195 if (!drv_data) 196 return -ENOMEM; 197 198 drv_data->i2c_client = i2c_client; 199 200 ret = menf21bmc_hwmon_get_volt_limits(drv_data); 201 if (ret) { 202 dev_err(&pdev->dev, "failed to read sensor limits"); 203 return ret; 204 } 205 206 hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev, 207 "menf21bmc", drv_data, 208 menf21bmc_hwmon_groups); 209 if (IS_ERR(hwmon_dev)) 210 return PTR_ERR(hwmon_dev); 211 212 dev_info(&pdev->dev, "MEN 14F021P00 BMC hwmon device enabled"); 213 214 return 0; 215 } 216 217 static struct platform_driver menf21bmc_hwmon = { 218 .probe = menf21bmc_hwmon_probe, 219 .driver = { 220 .name = DRV_NAME, 221 .owner = THIS_MODULE, 222 }, 223 }; 224 225 module_platform_driver(menf21bmc_hwmon); 226 227 MODULE_AUTHOR("Andreas Werner <andreas.werner@men.de>"); 228 MODULE_DESCRIPTION("MEN 14F021P00 BMC hwmon"); 229 MODULE_LICENSE("GPL v2"); 230 MODULE_ALIAS("platform:menf21bmc_hwmon"); 231