diff options
author | Guenter Roeck <linux@roeck-us.net> | 2014-09-24 12:25:06 -0400 |
---|---|---|
committer | Guenter Roeck <linux@roeck-us.net> | 2014-09-24 12:25:06 -0400 |
commit | 7ad8966f4f0a4606dfaba119ea4e2b3ac4c548ee (patch) | |
tree | 38a7548d5a36cc20145eb916319fe673b84341b1 /drivers/hwmon | |
parent | c08860ffe5c0e986e208e8217dae8191c0b40b24 (diff) | |
parent | 964356938fcd3c0001a786f55b9f0a0fbe47656a (diff) |
Merge tag 'mfd-hwmon-leds-watchdog-v3.18' into hwmon-next
Immutable branch between MFD, HWMON, LEDs and Watchdog for v3.18
Diffstat (limited to 'drivers/hwmon')
-rw-r--r-- | drivers/hwmon/Kconfig | 10 | ||||
-rw-r--r-- | drivers/hwmon/Makefile | 1 | ||||
-rw-r--r-- | drivers/hwmon/menf21bmc_hwmon.c | 230 |
3 files changed, 241 insertions, 0 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index f790b41283d0..5286d7ce1f9e 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig | |||
@@ -839,6 +839,16 @@ config SENSORS_MCP3021 | |||
839 | This driver can also be built as a module. If so, the module | 839 | This driver can also be built as a module. If so, the module |
840 | will be called mcp3021. | 840 | will be called mcp3021. |
841 | 841 | ||
842 | config SENSORS_MENF21BMC_HWMON | ||
843 | tristate "MEN 14F021P00 BMC Hardware Monitoring" | ||
844 | depends on MFD_MENF21BMC | ||
845 | help | ||
846 | Say Y here to include support for the MEN 14F021P00 BMC | ||
847 | hardware monitoring. | ||
848 | |||
849 | This driver can also be built as a module. If so the module | ||
850 | will be called menf21bmc_hwmon. | ||
851 | |||
842 | config SENSORS_ADCXX | 852 | config SENSORS_ADCXX |
843 | tristate "National Semiconductor ADCxxxSxxx" | 853 | tristate "National Semiconductor ADCxxxSxxx" |
844 | depends on SPI_MASTER | 854 | depends on SPI_MASTER |
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index be28152c9848..c90a7611efaa 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile | |||
@@ -115,6 +115,7 @@ obj-$(CONFIG_SENSORS_MAX6650) += max6650.o | |||
115 | obj-$(CONFIG_SENSORS_MAX6697) += max6697.o | 115 | obj-$(CONFIG_SENSORS_MAX6697) += max6697.o |
116 | obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o | 116 | obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o |
117 | obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o | 117 | obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o |
118 | obj-$(CONFIG_SENSORS_MENF21BMC_HWMON) += menf21bmc_hwmon.o | ||
118 | obj-$(CONFIG_SENSORS_NCT6683) += nct6683.o | 119 | obj-$(CONFIG_SENSORS_NCT6683) += nct6683.o |
119 | obj-$(CONFIG_SENSORS_NCT6775) += nct6775.o | 120 | obj-$(CONFIG_SENSORS_NCT6775) += nct6775.o |
120 | obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o | 121 | obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o |
diff --git a/drivers/hwmon/menf21bmc_hwmon.c b/drivers/hwmon/menf21bmc_hwmon.c new file mode 100644 index 000000000000..c92229d321c9 --- /dev/null +++ b/drivers/hwmon/menf21bmc_hwmon.c | |||
@@ -0,0 +1,230 @@ | |||
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"); | ||