Skip to content

Commit 442aba7

Browse files
author
Guenter Roeck
committed
hwmon: PMBus device driver
This driver adds support for hardware monitoring features of various PMBus devices. Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com> Acked-by: Jonathan Cameron <jic23@cam.ac.uk>
1 parent 06923f8 commit 442aba7

File tree

6 files changed

+2218
-0
lines changed

6 files changed

+2218
-0
lines changed

drivers/hwmon/Kconfig

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -756,6 +756,31 @@ config SENSORS_PCF8591
756756
These devices are hard to detect and rarely found on mainstream
757757
hardware. If unsure, say N.
758758

759+
config PMBUS
760+
tristate "PMBus support"
761+
depends on I2C && EXPERIMENTAL
762+
default n
763+
help
764+
Say yes here if you want to enable PMBus support.
765+
766+
This driver can also be built as a module. If so, the module will
767+
be called pmbus_core.
768+
769+
if PMBUS
770+
771+
config SENSORS_PMBUS
772+
tristate "Generic PMBus devices"
773+
default n
774+
help
775+
If you say yes here you get hardware monitoring support for generic
776+
PMBus devices, including but not limited to BMR450, BMR451, BMR453,
777+
BMR454, and LTC2978.
778+
779+
This driver can also be built as a module. If so, the module will
780+
be called pmbus.
781+
782+
endif # PMBUS
783+
759784
config SENSORS_SHT15
760785
tristate "Sensiron humidity and temperature sensors. SHT15 and compat."
761786
depends on GENERIC_GPIO

drivers/hwmon/Makefile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o
114114
obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o
115115
obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o
116116

117+
# PMBus drivers
118+
obj-$(CONFIG_PMBUS) += pmbus_core.o
119+
obj-$(CONFIG_SENSORS_PMBUS) += pmbus.o
120+
117121
ifeq ($(CONFIG_HWMON_DEBUG_CHIP),y)
118122
EXTRA_CFLAGS += -DDEBUG
119123
endif

drivers/hwmon/pmbus.c

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
/*
2+
* Hardware monitoring driver for PMBus devices
3+
*
4+
* Copyright (c) 2010, 2011 Ericsson AB.
5+
*
6+
* This program is free software; you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation; either version 2 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with this program; if not, write to the Free Software
18+
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19+
*/
20+
21+
#include <linux/kernel.h>
22+
#include <linux/module.h>
23+
#include <linux/init.h>
24+
#include <linux/err.h>
25+
#include <linux/slab.h>
26+
#include <linux/mutex.h>
27+
#include <linux/i2c.h>
28+
#include "pmbus.h"
29+
30+
/*
31+
* Find sensor groups and status registers on each page.
32+
*/
33+
static void pmbus_find_sensor_groups(struct i2c_client *client,
34+
struct pmbus_driver_info *info)
35+
{
36+
int page;
37+
38+
/* Sensors detected on page 0 only */
39+
if (pmbus_check_word_register(client, 0, PMBUS_READ_VIN))
40+
info->func[0] |= PMBUS_HAVE_VIN;
41+
if (pmbus_check_word_register(client, 0, PMBUS_READ_VCAP))
42+
info->func[0] |= PMBUS_HAVE_VCAP;
43+
if (pmbus_check_word_register(client, 0, PMBUS_READ_IIN))
44+
info->func[0] |= PMBUS_HAVE_IIN;
45+
if (pmbus_check_word_register(client, 0, PMBUS_READ_PIN))
46+
info->func[0] |= PMBUS_HAVE_PIN;
47+
if (info->func[0]
48+
&& pmbus_check_byte_register(client, 0, PMBUS_STATUS_INPUT))
49+
info->func[0] |= PMBUS_HAVE_STATUS_INPUT;
50+
if (pmbus_check_word_register(client, 0, PMBUS_READ_FAN_SPEED_1)) {
51+
info->func[0] |= PMBUS_HAVE_FAN12;
52+
if (pmbus_check_byte_register(client, 0, PMBUS_STATUS_FAN_12))
53+
info->func[0] |= PMBUS_HAVE_STATUS_FAN12;
54+
}
55+
if (pmbus_check_word_register(client, 0, PMBUS_READ_FAN_SPEED_3)) {
56+
info->func[0] |= PMBUS_HAVE_FAN34;
57+
if (pmbus_check_byte_register(client, 0, PMBUS_STATUS_FAN_34))
58+
info->func[0] |= PMBUS_HAVE_STATUS_FAN34;
59+
}
60+
if (pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_1)) {
61+
info->func[0] |= PMBUS_HAVE_TEMP;
62+
if (pmbus_check_byte_register(client, 0,
63+
PMBUS_STATUS_TEMPERATURE))
64+
info->func[0] |= PMBUS_HAVE_STATUS_TEMP;
65+
}
66+
67+
/* Sensors detected on all pages */
68+
for (page = 0; page < info->pages; page++) {
69+
if (pmbus_check_word_register(client, page, PMBUS_READ_VOUT)) {
70+
info->func[page] |= PMBUS_HAVE_VOUT;
71+
if (pmbus_check_byte_register(client, page,
72+
PMBUS_STATUS_VOUT))
73+
info->func[page] |= PMBUS_HAVE_STATUS_VOUT;
74+
}
75+
if (pmbus_check_word_register(client, page, PMBUS_READ_IOUT)) {
76+
info->func[page] |= PMBUS_HAVE_IOUT;
77+
if (pmbus_check_byte_register(client, 0,
78+
PMBUS_STATUS_IOUT))
79+
info->func[page] |= PMBUS_HAVE_STATUS_IOUT;
80+
}
81+
if (pmbus_check_word_register(client, page, PMBUS_READ_POUT))
82+
info->func[page] |= PMBUS_HAVE_POUT;
83+
}
84+
}
85+
86+
/*
87+
* Identify chip parameters.
88+
*/
89+
static int pmbus_identify(struct i2c_client *client,
90+
struct pmbus_driver_info *info)
91+
{
92+
if (!info->pages) {
93+
/*
94+
* Check if the PAGE command is supported. If it is,
95+
* keep setting the page number until it fails or until the
96+
* maximum number of pages has been reached. Assume that
97+
* this is the number of pages supported by the chip.
98+
*/
99+
if (pmbus_check_byte_register(client, 0, PMBUS_PAGE)) {
100+
int page;
101+
102+
for (page = 1; page < PMBUS_PAGES; page++) {
103+
if (pmbus_set_page(client, page) < 0)
104+
break;
105+
}
106+
pmbus_set_page(client, 0);
107+
info->pages = page;
108+
} else {
109+
info->pages = 1;
110+
}
111+
}
112+
113+
/*
114+
* We should check if the COEFFICIENTS register is supported.
115+
* If it is, and the chip is configured for direct mode, we can read
116+
* the coefficients from the chip, one set per group of sensor
117+
* registers.
118+
*
119+
* To do this, we will need access to a chip which actually supports the
120+
* COEFFICIENTS command, since the command is too complex to implement
121+
* without testing it.
122+
*/
123+
124+
/* Try to find sensor groups */
125+
pmbus_find_sensor_groups(client, info);
126+
127+
return 0;
128+
}
129+
130+
static int pmbus_probe(struct i2c_client *client,
131+
const struct i2c_device_id *id)
132+
{
133+
struct pmbus_driver_info *info;
134+
int ret;
135+
136+
info = kzalloc(sizeof(struct pmbus_driver_info), GFP_KERNEL);
137+
if (!info)
138+
return -ENOMEM;
139+
140+
info->pages = id->driver_data;
141+
info->identify = pmbus_identify;
142+
143+
ret = pmbus_do_probe(client, id, info);
144+
if (ret < 0)
145+
goto out;
146+
return 0;
147+
148+
out:
149+
kfree(info);
150+
return ret;
151+
}
152+
153+
static int pmbus_remove(struct i2c_client *client)
154+
{
155+
int ret;
156+
const struct pmbus_driver_info *info;
157+
158+
info = pmbus_get_driver_info(client);
159+
ret = pmbus_do_remove(client);
160+
kfree(info);
161+
return ret;
162+
}
163+
164+
/*
165+
* Use driver_data to set the number of pages supported by the chip.
166+
*/
167+
static const struct i2c_device_id pmbus_id[] = {
168+
{"bmr450", 1},
169+
{"bmr451", 1},
170+
{"bmr453", 1},
171+
{"bmr454", 1},
172+
{"ltc2978", 8},
173+
{"pmbus", 0},
174+
{}
175+
};
176+
177+
MODULE_DEVICE_TABLE(i2c, pmbus_id);
178+
179+
/* This is the driver that will be inserted */
180+
static struct i2c_driver pmbus_driver = {
181+
.driver = {
182+
.name = "pmbus",
183+
},
184+
.probe = pmbus_probe,
185+
.remove = pmbus_remove,
186+
.id_table = pmbus_id,
187+
};
188+
189+
static int __init pmbus_init(void)
190+
{
191+
return i2c_add_driver(&pmbus_driver);
192+
}
193+
194+
static void __exit pmbus_exit(void)
195+
{
196+
i2c_del_driver(&pmbus_driver);
197+
}
198+
199+
MODULE_AUTHOR("Guenter Roeck");
200+
MODULE_DESCRIPTION("Generic PMBus driver");
201+
MODULE_LICENSE("GPL");
202+
module_init(pmbus_init);
203+
module_exit(pmbus_exit);

0 commit comments

Comments
 (0)