diff options
author | Guenter Roeck <guenter.roeck@ericsson.com> | 2011-07-12 10:15:19 -0400 |
---|---|---|
committer | Guenter Roeck <guenter.roeck@ericsson.com> | 2011-07-28 14:47:53 -0400 |
commit | 9d2ecfb768bd2f8b41816a23b0f1dda026fef41d (patch) | |
tree | 7424d830c0b8475d2c872ec0bd1953b354c01094 /drivers/hwmon/pmbus | |
parent | c814a4c7c4aad795835583344353963a0a673eb0 (diff) |
hwmon: (pmbus) Move PMBus drivers to drivers/hwmon/pmbus
Since the number of PMBus drivers is getting large, move them into
directory drivers/hwmon/pmbus to improve readability and scalability.
Signed-off-by: Guenter Roeck <guenter.roeck@ericsson.com>
Reviewed-by: Robert Coulson <robert.coulson@ericsson.com>
Diffstat (limited to 'drivers/hwmon/pmbus')
-rw-r--r-- | drivers/hwmon/pmbus/Kconfig | 90 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/Makefile | 12 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/adm1275.c | 131 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/max16064.c | 91 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/max34440.c | 199 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/max8688.c | 158 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/pmbus.c | 210 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/pmbus.h | 311 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/pmbus_core.c | 1567 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/ucd9000.c | 278 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/ucd9200.c | 210 |
11 files changed, 3257 insertions, 0 deletions
diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig new file mode 100644 index 000000000000..794129f48594 --- /dev/null +++ b/drivers/hwmon/pmbus/Kconfig | |||
@@ -0,0 +1,90 @@ | |||
1 | # | ||
2 | # PMBus chip drivers configuration | ||
3 | # | ||
4 | |||
5 | menuconfig PMBUS | ||
6 | tristate "PMBus support" | ||
7 | depends on I2C && EXPERIMENTAL | ||
8 | default n | ||
9 | help | ||
10 | Say yes here if you want to enable PMBus support. | ||
11 | |||
12 | This driver can also be built as a module. If so, the module will | ||
13 | be called pmbus_core. | ||
14 | |||
15 | if PMBUS | ||
16 | |||
17 | config SENSORS_PMBUS | ||
18 | tristate "Generic PMBus devices" | ||
19 | default y | ||
20 | help | ||
21 | If you say yes here you get hardware monitoring support for generic | ||
22 | PMBus devices, including but not limited to BMR450, BMR451, BMR453, | ||
23 | BMR454, and LTC2978. | ||
24 | |||
25 | This driver can also be built as a module. If so, the module will | ||
26 | be called pmbus. | ||
27 | |||
28 | config SENSORS_ADM1275 | ||
29 | tristate "Analog Devices ADM1275" | ||
30 | default n | ||
31 | help | ||
32 | If you say yes here you get hardware monitoring support for Analog | ||
33 | Devices ADM1275 Hot-Swap Controller and Digital Power Monitor. | ||
34 | |||
35 | This driver can also be built as a module. If so, the module will | ||
36 | be called adm1275. | ||
37 | |||
38 | config SENSORS_MAX16064 | ||
39 | tristate "Maxim MAX16064" | ||
40 | default n | ||
41 | help | ||
42 | If you say yes here you get hardware monitoring support for Maxim | ||
43 | MAX16064. | ||
44 | |||
45 | This driver can also be built as a module. If so, the module will | ||
46 | be called max16064. | ||
47 | |||
48 | config SENSORS_MAX34440 | ||
49 | tristate "Maxim MAX34440/MAX34441" | ||
50 | default n | ||
51 | help | ||
52 | If you say yes here you get hardware monitoring support for Maxim | ||
53 | MAX34440 and MAX34441. | ||
54 | |||
55 | This driver can also be built as a module. If so, the module will | ||
56 | be called max34440. | ||
57 | |||
58 | config SENSORS_MAX8688 | ||
59 | tristate "Maxim MAX8688" | ||
60 | default n | ||
61 | help | ||
62 | If you say yes here you get hardware monitoring support for Maxim | ||
63 | MAX8688. | ||
64 | |||
65 | This driver can also be built as a module. If so, the module will | ||
66 | be called max8688. | ||
67 | |||
68 | config SENSORS_UCD9000 | ||
69 | tristate "TI UCD90120, UCD90124, UCD9090, UCD90910" | ||
70 | default n | ||
71 | help | ||
72 | If you say yes here you get hardware monitoring support for TI | ||
73 | UCD90120, UCD90124, UCD9090, UCD90910 Sequencer and System Health | ||
74 | Controllers. | ||
75 | |||
76 | This driver can also be built as a module. If so, the module will | ||
77 | be called ucd9000. | ||
78 | |||
79 | config SENSORS_UCD9200 | ||
80 | tristate "TI UCD9220, UCD9222, UCD9224, UCD9240, UCD9244, UCD9246, UCD9248" | ||
81 | default n | ||
82 | help | ||
83 | If you say yes here you get hardware monitoring support for TI | ||
84 | UCD9220, UCD9222, UCD9224, UCD9240, UCD9244, UCD9246, and UCD9248 | ||
85 | Digital PWM System Controllers. | ||
86 | |||
87 | This driver can also be built as a module. If so, the module will | ||
88 | be called ucd9200. | ||
89 | |||
90 | endif # PMBUS | ||
diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile new file mode 100644 index 000000000000..0178f81829d0 --- /dev/null +++ b/drivers/hwmon/pmbus/Makefile | |||
@@ -0,0 +1,12 @@ | |||
1 | # | ||
2 | # Makefile for PMBus chip drivers. | ||
3 | # | ||
4 | |||
5 | obj-$(CONFIG_PMBUS) += pmbus_core.o | ||
6 | obj-$(CONFIG_SENSORS_PMBUS) += pmbus.o | ||
7 | obj-$(CONFIG_SENSORS_ADM1275) += adm1275.o | ||
8 | obj-$(CONFIG_SENSORS_MAX16064) += max16064.o | ||
9 | obj-$(CONFIG_SENSORS_MAX34440) += max34440.o | ||
10 | obj-$(CONFIG_SENSORS_MAX8688) += max8688.o | ||
11 | obj-$(CONFIG_SENSORS_UCD9000) += ucd9000.o | ||
12 | obj-$(CONFIG_SENSORS_UCD9200) += ucd9200.o | ||
diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c new file mode 100644 index 000000000000..8bc1bd663721 --- /dev/null +++ b/drivers/hwmon/pmbus/adm1275.c | |||
@@ -0,0 +1,131 @@ | |||
1 | /* | ||
2 | * Hardware monitoring driver for Analog Devices ADM1275 Hot-Swap Controller | ||
3 | * and Digital Power Monitor | ||
4 | * | ||
5 | * Copyright (c) 2011 Ericsson AB. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/err.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/i2c.h> | ||
24 | #include "pmbus.h" | ||
25 | |||
26 | #define ADM1275_PMON_CONFIG 0xd4 | ||
27 | |||
28 | #define ADM1275_VIN_VOUT_SELECT (1 << 6) | ||
29 | #define ADM1275_VRANGE (1 << 5) | ||
30 | |||
31 | static int adm1275_probe(struct i2c_client *client, | ||
32 | const struct i2c_device_id *id) | ||
33 | { | ||
34 | int config; | ||
35 | int ret; | ||
36 | struct pmbus_driver_info *info; | ||
37 | |||
38 | if (!i2c_check_functionality(client->adapter, | ||
39 | I2C_FUNC_SMBUS_READ_BYTE_DATA)) | ||
40 | return -ENODEV; | ||
41 | |||
42 | info = kzalloc(sizeof(struct pmbus_driver_info), GFP_KERNEL); | ||
43 | if (!info) | ||
44 | return -ENOMEM; | ||
45 | |||
46 | config = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG); | ||
47 | if (config < 0) { | ||
48 | ret = config; | ||
49 | goto err_mem; | ||
50 | } | ||
51 | |||
52 | info->pages = 1; | ||
53 | info->direct[PSC_VOLTAGE_IN] = true; | ||
54 | info->direct[PSC_VOLTAGE_OUT] = true; | ||
55 | info->direct[PSC_CURRENT_OUT] = true; | ||
56 | info->m[PSC_CURRENT_OUT] = 807; | ||
57 | info->b[PSC_CURRENT_OUT] = 20475; | ||
58 | info->R[PSC_CURRENT_OUT] = -1; | ||
59 | info->func[0] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT; | ||
60 | |||
61 | if (config & ADM1275_VRANGE) { | ||
62 | info->m[PSC_VOLTAGE_IN] = 19199; | ||
63 | info->b[PSC_VOLTAGE_IN] = 0; | ||
64 | info->R[PSC_VOLTAGE_IN] = -2; | ||
65 | info->m[PSC_VOLTAGE_OUT] = 19199; | ||
66 | info->b[PSC_VOLTAGE_OUT] = 0; | ||
67 | info->R[PSC_VOLTAGE_OUT] = -2; | ||
68 | } else { | ||
69 | info->m[PSC_VOLTAGE_IN] = 6720; | ||
70 | info->b[PSC_VOLTAGE_IN] = 0; | ||
71 | info->R[PSC_VOLTAGE_IN] = -1; | ||
72 | info->m[PSC_VOLTAGE_OUT] = 6720; | ||
73 | info->b[PSC_VOLTAGE_OUT] = 0; | ||
74 | info->R[PSC_VOLTAGE_OUT] = -1; | ||
75 | } | ||
76 | |||
77 | if (config & ADM1275_VIN_VOUT_SELECT) | ||
78 | info->func[0] |= PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT; | ||
79 | else | ||
80 | info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT; | ||
81 | |||
82 | ret = pmbus_do_probe(client, id, info); | ||
83 | if (ret) | ||
84 | goto err_mem; | ||
85 | return 0; | ||
86 | |||
87 | err_mem: | ||
88 | kfree(info); | ||
89 | return ret; | ||
90 | } | ||
91 | |||
92 | static int adm1275_remove(struct i2c_client *client) | ||
93 | { | ||
94 | const struct pmbus_driver_info *info = pmbus_get_driver_info(client); | ||
95 | int ret; | ||
96 | |||
97 | ret = pmbus_do_remove(client); | ||
98 | kfree(info); | ||
99 | return ret; | ||
100 | } | ||
101 | |||
102 | static const struct i2c_device_id adm1275_id[] = { | ||
103 | {"adm1275", 0}, | ||
104 | { } | ||
105 | }; | ||
106 | MODULE_DEVICE_TABLE(i2c, adm1275_id); | ||
107 | |||
108 | static struct i2c_driver adm1275_driver = { | ||
109 | .driver = { | ||
110 | .name = "adm1275", | ||
111 | }, | ||
112 | .probe = adm1275_probe, | ||
113 | .remove = adm1275_remove, | ||
114 | .id_table = adm1275_id, | ||
115 | }; | ||
116 | |||
117 | static int __init adm1275_init(void) | ||
118 | { | ||
119 | return i2c_add_driver(&adm1275_driver); | ||
120 | } | ||
121 | |||
122 | static void __exit adm1275_exit(void) | ||
123 | { | ||
124 | i2c_del_driver(&adm1275_driver); | ||
125 | } | ||
126 | |||
127 | MODULE_AUTHOR("Guenter Roeck"); | ||
128 | MODULE_DESCRIPTION("PMBus driver for Analog Devices ADM1275"); | ||
129 | MODULE_LICENSE("GPL"); | ||
130 | module_init(adm1275_init); | ||
131 | module_exit(adm1275_exit); | ||
diff --git a/drivers/hwmon/pmbus/max16064.c b/drivers/hwmon/pmbus/max16064.c new file mode 100644 index 000000000000..1d6d717060d3 --- /dev/null +++ b/drivers/hwmon/pmbus/max16064.c | |||
@@ -0,0 +1,91 @@ | |||
1 | /* | ||
2 | * Hardware monitoring driver for Maxim MAX16064 | ||
3 | * | ||
4 | * Copyright (c) 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/i2c.h> | ||
26 | #include "pmbus.h" | ||
27 | |||
28 | static struct pmbus_driver_info max16064_info = { | ||
29 | .pages = 4, | ||
30 | .direct[PSC_VOLTAGE_IN] = true, | ||
31 | .direct[PSC_VOLTAGE_OUT] = true, | ||
32 | .direct[PSC_TEMPERATURE] = true, | ||
33 | .m[PSC_VOLTAGE_IN] = 19995, | ||
34 | .b[PSC_VOLTAGE_IN] = 0, | ||
35 | .R[PSC_VOLTAGE_IN] = -1, | ||
36 | .m[PSC_VOLTAGE_OUT] = 19995, | ||
37 | .b[PSC_VOLTAGE_OUT] = 0, | ||
38 | .R[PSC_VOLTAGE_OUT] = -1, | ||
39 | .m[PSC_TEMPERATURE] = -7612, | ||
40 | .b[PSC_TEMPERATURE] = 335, | ||
41 | .R[PSC_TEMPERATURE] = -3, | ||
42 | .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_TEMP | ||
43 | | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_TEMP, | ||
44 | .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT, | ||
45 | .func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT, | ||
46 | .func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT, | ||
47 | }; | ||
48 | |||
49 | static int max16064_probe(struct i2c_client *client, | ||
50 | const struct i2c_device_id *id) | ||
51 | { | ||
52 | return pmbus_do_probe(client, id, &max16064_info); | ||
53 | } | ||
54 | |||
55 | static int max16064_remove(struct i2c_client *client) | ||
56 | { | ||
57 | return pmbus_do_remove(client); | ||
58 | } | ||
59 | |||
60 | static const struct i2c_device_id max16064_id[] = { | ||
61 | {"max16064", 0}, | ||
62 | {} | ||
63 | }; | ||
64 | |||
65 | MODULE_DEVICE_TABLE(i2c, max16064_id); | ||
66 | |||
67 | /* This is the driver that will be inserted */ | ||
68 | static struct i2c_driver max16064_driver = { | ||
69 | .driver = { | ||
70 | .name = "max16064", | ||
71 | }, | ||
72 | .probe = max16064_probe, | ||
73 | .remove = max16064_remove, | ||
74 | .id_table = max16064_id, | ||
75 | }; | ||
76 | |||
77 | static int __init max16064_init(void) | ||
78 | { | ||
79 | return i2c_add_driver(&max16064_driver); | ||
80 | } | ||
81 | |||
82 | static void __exit max16064_exit(void) | ||
83 | { | ||
84 | i2c_del_driver(&max16064_driver); | ||
85 | } | ||
86 | |||
87 | MODULE_AUTHOR("Guenter Roeck"); | ||
88 | MODULE_DESCRIPTION("PMBus driver for Maxim MAX16064"); | ||
89 | MODULE_LICENSE("GPL"); | ||
90 | module_init(max16064_init); | ||
91 | module_exit(max16064_exit); | ||
diff --git a/drivers/hwmon/pmbus/max34440.c b/drivers/hwmon/pmbus/max34440.c new file mode 100644 index 000000000000..db11e1a175b2 --- /dev/null +++ b/drivers/hwmon/pmbus/max34440.c | |||
@@ -0,0 +1,199 @@ | |||
1 | /* | ||
2 | * Hardware monitoring driver for Maxim MAX34440/MAX34441 | ||
3 | * | ||
4 | * Copyright (c) 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/i2c.h> | ||
26 | #include "pmbus.h" | ||
27 | |||
28 | enum chips { max34440, max34441 }; | ||
29 | |||
30 | #define MAX34440_STATUS_OC_WARN (1 << 0) | ||
31 | #define MAX34440_STATUS_OC_FAULT (1 << 1) | ||
32 | #define MAX34440_STATUS_OT_FAULT (1 << 5) | ||
33 | #define MAX34440_STATUS_OT_WARN (1 << 6) | ||
34 | |||
35 | static int max34440_read_byte_data(struct i2c_client *client, int page, int reg) | ||
36 | { | ||
37 | int ret; | ||
38 | int mfg_status; | ||
39 | |||
40 | ret = pmbus_set_page(client, page); | ||
41 | if (ret < 0) | ||
42 | return ret; | ||
43 | |||
44 | switch (reg) { | ||
45 | case PMBUS_STATUS_IOUT: | ||
46 | mfg_status = pmbus_read_word_data(client, 0, | ||
47 | PMBUS_STATUS_MFR_SPECIFIC); | ||
48 | if (mfg_status < 0) | ||
49 | return mfg_status; | ||
50 | if (mfg_status & MAX34440_STATUS_OC_WARN) | ||
51 | ret |= PB_IOUT_OC_WARNING; | ||
52 | if (mfg_status & MAX34440_STATUS_OC_FAULT) | ||
53 | ret |= PB_IOUT_OC_FAULT; | ||
54 | break; | ||
55 | case PMBUS_STATUS_TEMPERATURE: | ||
56 | mfg_status = pmbus_read_word_data(client, 0, | ||
57 | PMBUS_STATUS_MFR_SPECIFIC); | ||
58 | if (mfg_status < 0) | ||
59 | return mfg_status; | ||
60 | if (mfg_status & MAX34440_STATUS_OT_WARN) | ||
61 | ret |= PB_TEMP_OT_WARNING; | ||
62 | if (mfg_status & MAX34440_STATUS_OT_FAULT) | ||
63 | ret |= PB_TEMP_OT_FAULT; | ||
64 | break; | ||
65 | default: | ||
66 | ret = -ENODATA; | ||
67 | break; | ||
68 | } | ||
69 | return ret; | ||
70 | } | ||
71 | |||
72 | static struct pmbus_driver_info max34440_info[] = { | ||
73 | [max34440] = { | ||
74 | .pages = 14, | ||
75 | .direct[PSC_VOLTAGE_IN] = true, | ||
76 | .direct[PSC_VOLTAGE_OUT] = true, | ||
77 | .direct[PSC_TEMPERATURE] = true, | ||
78 | .direct[PSC_CURRENT_OUT] = true, | ||
79 | .m[PSC_VOLTAGE_IN] = 1, | ||
80 | .b[PSC_VOLTAGE_IN] = 0, | ||
81 | .R[PSC_VOLTAGE_IN] = 3, /* R = 0 in datasheet reflects mV */ | ||
82 | .m[PSC_VOLTAGE_OUT] = 1, | ||
83 | .b[PSC_VOLTAGE_OUT] = 0, | ||
84 | .R[PSC_VOLTAGE_OUT] = 3, /* R = 0 in datasheet reflects mV */ | ||
85 | .m[PSC_CURRENT_OUT] = 1, | ||
86 | .b[PSC_CURRENT_OUT] = 0, | ||
87 | .R[PSC_CURRENT_OUT] = 3, /* R = 0 in datasheet reflects mA */ | ||
88 | .m[PSC_TEMPERATURE] = 1, | ||
89 | .b[PSC_TEMPERATURE] = 0, | ||
90 | .R[PSC_TEMPERATURE] = 2, | ||
91 | .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | ||
92 | | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, | ||
93 | .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | ||
94 | | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, | ||
95 | .func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | ||
96 | | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, | ||
97 | .func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | ||
98 | | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, | ||
99 | .func[4] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | ||
100 | | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, | ||
101 | .func[5] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | ||
102 | | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, | ||
103 | .func[6] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, | ||
104 | .func[7] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, | ||
105 | .func[8] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, | ||
106 | .func[9] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, | ||
107 | .func[10] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, | ||
108 | .func[11] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, | ||
109 | .func[12] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, | ||
110 | .func[13] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, | ||
111 | .read_byte_data = max34440_read_byte_data, | ||
112 | }, | ||
113 | [max34441] = { | ||
114 | .pages = 12, | ||
115 | .direct[PSC_VOLTAGE_IN] = true, | ||
116 | .direct[PSC_VOLTAGE_OUT] = true, | ||
117 | .direct[PSC_TEMPERATURE] = true, | ||
118 | .direct[PSC_CURRENT_OUT] = true, | ||
119 | .direct[PSC_FAN] = true, | ||
120 | .m[PSC_VOLTAGE_IN] = 1, | ||
121 | .b[PSC_VOLTAGE_IN] = 0, | ||
122 | .R[PSC_VOLTAGE_IN] = 3, | ||
123 | .m[PSC_VOLTAGE_OUT] = 1, | ||
124 | .b[PSC_VOLTAGE_OUT] = 0, | ||
125 | .R[PSC_VOLTAGE_OUT] = 3, | ||
126 | .m[PSC_CURRENT_OUT] = 1, | ||
127 | .b[PSC_CURRENT_OUT] = 0, | ||
128 | .R[PSC_CURRENT_OUT] = 3, | ||
129 | .m[PSC_TEMPERATURE] = 1, | ||
130 | .b[PSC_TEMPERATURE] = 0, | ||
131 | .R[PSC_TEMPERATURE] = 2, | ||
132 | .m[PSC_FAN] = 1, | ||
133 | .b[PSC_FAN] = 0, | ||
134 | .R[PSC_FAN] = 0, | ||
135 | .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | ||
136 | | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, | ||
137 | .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | ||
138 | | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, | ||
139 | .func[2] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | ||
140 | | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, | ||
141 | .func[3] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | ||
142 | | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, | ||
143 | .func[4] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | ||
144 | | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, | ||
145 | .func[5] = PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12, | ||
146 | .func[6] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, | ||
147 | .func[7] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, | ||
148 | .func[8] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, | ||
149 | .func[9] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, | ||
150 | .func[10] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, | ||
151 | .func[11] = PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP, | ||
152 | .read_byte_data = max34440_read_byte_data, | ||
153 | }, | ||
154 | }; | ||
155 | |||
156 | static int max34440_probe(struct i2c_client *client, | ||
157 | const struct i2c_device_id *id) | ||
158 | { | ||
159 | return pmbus_do_probe(client, id, &max34440_info[id->driver_data]); | ||
160 | } | ||
161 | |||
162 | static int max34440_remove(struct i2c_client *client) | ||
163 | { | ||
164 | return pmbus_do_remove(client); | ||
165 | } | ||
166 | |||
167 | static const struct i2c_device_id max34440_id[] = { | ||
168 | {"max34440", max34440}, | ||
169 | {"max34441", max34441}, | ||
170 | {} | ||
171 | }; | ||
172 | |||
173 | MODULE_DEVICE_TABLE(i2c, max34440_id); | ||
174 | |||
175 | /* This is the driver that will be inserted */ | ||
176 | static struct i2c_driver max34440_driver = { | ||
177 | .driver = { | ||
178 | .name = "max34440", | ||
179 | }, | ||
180 | .probe = max34440_probe, | ||
181 | .remove = max34440_remove, | ||
182 | .id_table = max34440_id, | ||
183 | }; | ||
184 | |||
185 | static int __init max34440_init(void) | ||
186 | { | ||
187 | return i2c_add_driver(&max34440_driver); | ||
188 | } | ||
189 | |||
190 | static void __exit max34440_exit(void) | ||
191 | { | ||
192 | i2c_del_driver(&max34440_driver); | ||
193 | } | ||
194 | |||
195 | MODULE_AUTHOR("Guenter Roeck"); | ||
196 | MODULE_DESCRIPTION("PMBus driver for Maxim MAX34440/MAX34441"); | ||
197 | MODULE_LICENSE("GPL"); | ||
198 | module_init(max34440_init); | ||
199 | module_exit(max34440_exit); | ||
diff --git a/drivers/hwmon/pmbus/max8688.c b/drivers/hwmon/pmbus/max8688.c new file mode 100644 index 000000000000..7fb93f4e9f21 --- /dev/null +++ b/drivers/hwmon/pmbus/max8688.c | |||
@@ -0,0 +1,158 @@ | |||
1 | /* | ||
2 | * Hardware monitoring driver for Maxim MAX8688 | ||
3 | * | ||
4 | * Copyright (c) 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/i2c.h> | ||
26 | #include "pmbus.h" | ||
27 | |||
28 | #define MAX8688_MFG_STATUS 0xd8 | ||
29 | |||
30 | #define MAX8688_STATUS_OC_FAULT (1 << 4) | ||
31 | #define MAX8688_STATUS_OV_FAULT (1 << 5) | ||
32 | #define MAX8688_STATUS_OV_WARNING (1 << 8) | ||
33 | #define MAX8688_STATUS_UV_FAULT (1 << 9) | ||
34 | #define MAX8688_STATUS_UV_WARNING (1 << 10) | ||
35 | #define MAX8688_STATUS_UC_FAULT (1 << 11) | ||
36 | #define MAX8688_STATUS_OC_WARNING (1 << 12) | ||
37 | #define MAX8688_STATUS_OT_FAULT (1 << 13) | ||
38 | #define MAX8688_STATUS_OT_WARNING (1 << 14) | ||
39 | |||
40 | static int max8688_read_byte_data(struct i2c_client *client, int page, int reg) | ||
41 | { | ||
42 | int ret = 0; | ||
43 | int mfg_status; | ||
44 | |||
45 | if (page) | ||
46 | return -EINVAL; | ||
47 | |||
48 | switch (reg) { | ||
49 | case PMBUS_STATUS_VOUT: | ||
50 | mfg_status = pmbus_read_word_data(client, 0, | ||
51 | MAX8688_MFG_STATUS); | ||
52 | if (mfg_status < 0) | ||
53 | return mfg_status; | ||
54 | if (mfg_status & MAX8688_STATUS_UV_WARNING) | ||
55 | ret |= PB_VOLTAGE_UV_WARNING; | ||
56 | if (mfg_status & MAX8688_STATUS_UV_FAULT) | ||
57 | ret |= PB_VOLTAGE_UV_FAULT; | ||
58 | if (mfg_status & MAX8688_STATUS_OV_WARNING) | ||
59 | ret |= PB_VOLTAGE_OV_WARNING; | ||
60 | if (mfg_status & MAX8688_STATUS_OV_FAULT) | ||
61 | ret |= PB_VOLTAGE_OV_FAULT; | ||
62 | break; | ||
63 | case PMBUS_STATUS_IOUT: | ||
64 | mfg_status = pmbus_read_word_data(client, 0, | ||
65 | MAX8688_MFG_STATUS); | ||
66 | if (mfg_status < 0) | ||
67 | return mfg_status; | ||
68 | if (mfg_status & MAX8688_STATUS_UC_FAULT) | ||
69 | ret |= PB_IOUT_UC_FAULT; | ||
70 | if (mfg_status & MAX8688_STATUS_OC_WARNING) | ||
71 | ret |= PB_IOUT_OC_WARNING; | ||
72 | if (mfg_status & MAX8688_STATUS_OC_FAULT) | ||
73 | ret |= PB_IOUT_OC_FAULT; | ||
74 | break; | ||
75 | case PMBUS_STATUS_TEMPERATURE: | ||
76 | mfg_status = pmbus_read_word_data(client, 0, | ||
77 | MAX8688_MFG_STATUS); | ||
78 | if (mfg_status < 0) | ||
79 | return mfg_status; | ||
80 | if (mfg_status & MAX8688_STATUS_OT_WARNING) | ||
81 | ret |= PB_TEMP_OT_WARNING; | ||
82 | if (mfg_status & MAX8688_STATUS_OT_FAULT) | ||
83 | ret |= PB_TEMP_OT_FAULT; | ||
84 | break; | ||
85 | default: | ||
86 | ret = -ENODATA; | ||
87 | break; | ||
88 | } | ||
89 | return ret; | ||
90 | } | ||
91 | |||
92 | static struct pmbus_driver_info max8688_info = { | ||
93 | .pages = 1, | ||
94 | .direct[PSC_VOLTAGE_IN] = true, | ||
95 | .direct[PSC_VOLTAGE_OUT] = true, | ||
96 | .direct[PSC_TEMPERATURE] = true, | ||
97 | .direct[PSC_CURRENT_OUT] = true, | ||
98 | .m[PSC_VOLTAGE_IN] = 19995, | ||
99 | .b[PSC_VOLTAGE_IN] = 0, | ||
100 | .R[PSC_VOLTAGE_IN] = -1, | ||
101 | .m[PSC_VOLTAGE_OUT] = 19995, | ||
102 | .b[PSC_VOLTAGE_OUT] = 0, | ||
103 | .R[PSC_VOLTAGE_OUT] = -1, | ||
104 | .m[PSC_CURRENT_OUT] = 23109, | ||
105 | .b[PSC_CURRENT_OUT] = 0, | ||
106 | .R[PSC_CURRENT_OUT] = -2, | ||
107 | .m[PSC_TEMPERATURE] = -7612, | ||
108 | .b[PSC_TEMPERATURE] = 335, | ||
109 | .R[PSC_TEMPERATURE] = -3, | ||
110 | .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_IOUT | PMBUS_HAVE_TEMP | ||
111 | | PMBUS_HAVE_STATUS_VOUT | PMBUS_HAVE_STATUS_IOUT | ||
112 | | PMBUS_HAVE_STATUS_TEMP, | ||
113 | .read_byte_data = max8688_read_byte_data, | ||
114 | }; | ||
115 | |||
116 | static int max8688_probe(struct i2c_client *client, | ||
117 | const struct i2c_device_id *id) | ||
118 | { | ||
119 | return pmbus_do_probe(client, id, &max8688_info); | ||
120 | } | ||
121 | |||
122 | static int max8688_remove(struct i2c_client *client) | ||
123 | { | ||
124 | return pmbus_do_remove(client); | ||
125 | } | ||
126 | |||
127 | static const struct i2c_device_id max8688_id[] = { | ||
128 | {"max8688", 0}, | ||
129 | { } | ||
130 | }; | ||
131 | |||
132 | MODULE_DEVICE_TABLE(i2c, max8688_id); | ||
133 | |||
134 | /* This is the driver that will be inserted */ | ||
135 | static struct i2c_driver max8688_driver = { | ||
136 | .driver = { | ||
137 | .name = "max8688", | ||
138 | }, | ||
139 | .probe = max8688_probe, | ||
140 | .remove = max8688_remove, | ||
141 | .id_table = max8688_id, | ||
142 | }; | ||
143 | |||
144 | static int __init max8688_init(void) | ||
145 | { | ||
146 | return i2c_add_driver(&max8688_driver); | ||
147 | } | ||
148 | |||
149 | static void __exit max8688_exit(void) | ||
150 | { | ||
151 | i2c_del_driver(&max8688_driver); | ||
152 | } | ||
153 | |||
154 | MODULE_AUTHOR("Guenter Roeck"); | ||
155 | MODULE_DESCRIPTION("PMBus driver for Maxim MAX8688"); | ||
156 | MODULE_LICENSE("GPL"); | ||
157 | module_init(max8688_init); | ||
158 | module_exit(max8688_exit); | ||
diff --git a/drivers/hwmon/pmbus/pmbus.c b/drivers/hwmon/pmbus/pmbus.c new file mode 100644 index 000000000000..9b1f0c37ef77 --- /dev/null +++ b/drivers/hwmon/pmbus/pmbus.c | |||
@@ -0,0 +1,210 @@ | |||
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_byte_register(client, 0, PMBUS_FAN_CONFIG_12) && | ||
51 | pmbus_check_word_register(client, 0, PMBUS_READ_FAN_SPEED_1)) { | ||
52 | info->func[0] |= PMBUS_HAVE_FAN12; | ||
53 | if (pmbus_check_byte_register(client, 0, PMBUS_STATUS_FAN_12)) | ||
54 | info->func[0] |= PMBUS_HAVE_STATUS_FAN12; | ||
55 | } | ||
56 | if (pmbus_check_byte_register(client, 0, PMBUS_FAN_CONFIG_34) && | ||
57 | pmbus_check_word_register(client, 0, PMBUS_READ_FAN_SPEED_3)) { | ||
58 | info->func[0] |= PMBUS_HAVE_FAN34; | ||
59 | if (pmbus_check_byte_register(client, 0, PMBUS_STATUS_FAN_34)) | ||
60 | info->func[0] |= PMBUS_HAVE_STATUS_FAN34; | ||
61 | } | ||
62 | if (pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_1)) | ||
63 | info->func[0] |= PMBUS_HAVE_TEMP; | ||
64 | if (pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_2)) | ||
65 | info->func[0] |= PMBUS_HAVE_TEMP2; | ||
66 | if (pmbus_check_word_register(client, 0, PMBUS_READ_TEMPERATURE_3)) | ||
67 | info->func[0] |= PMBUS_HAVE_TEMP3; | ||
68 | if (info->func[0] & (PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | ||
69 | | PMBUS_HAVE_TEMP3) | ||
70 | && pmbus_check_byte_register(client, 0, | ||
71 | PMBUS_STATUS_TEMPERATURE)) | ||
72 | info->func[0] |= PMBUS_HAVE_STATUS_TEMP; | ||
73 | |||
74 | /* Sensors detected on all pages */ | ||
75 | for (page = 0; page < info->pages; page++) { | ||
76 | if (pmbus_check_word_register(client, page, PMBUS_READ_VOUT)) { | ||
77 | info->func[page] |= PMBUS_HAVE_VOUT; | ||
78 | if (pmbus_check_byte_register(client, page, | ||
79 | PMBUS_STATUS_VOUT)) | ||
80 | info->func[page] |= PMBUS_HAVE_STATUS_VOUT; | ||
81 | } | ||
82 | if (pmbus_check_word_register(client, page, PMBUS_READ_IOUT)) { | ||
83 | info->func[page] |= PMBUS_HAVE_IOUT; | ||
84 | if (pmbus_check_byte_register(client, 0, | ||
85 | PMBUS_STATUS_IOUT)) | ||
86 | info->func[page] |= PMBUS_HAVE_STATUS_IOUT; | ||
87 | } | ||
88 | if (pmbus_check_word_register(client, page, PMBUS_READ_POUT)) | ||
89 | info->func[page] |= PMBUS_HAVE_POUT; | ||
90 | } | ||
91 | } | ||
92 | |||
93 | /* | ||
94 | * Identify chip parameters. | ||
95 | */ | ||
96 | static int pmbus_identify(struct i2c_client *client, | ||
97 | struct pmbus_driver_info *info) | ||
98 | { | ||
99 | if (!info->pages) { | ||
100 | /* | ||
101 | * Check if the PAGE command is supported. If it is, | ||
102 | * keep setting the page number until it fails or until the | ||
103 | * maximum number of pages has been reached. Assume that | ||
104 | * this is the number of pages supported by the chip. | ||
105 | */ | ||
106 | if (pmbus_check_byte_register(client, 0, PMBUS_PAGE)) { | ||
107 | int page; | ||
108 | |||
109 | for (page = 1; page < PMBUS_PAGES; page++) { | ||
110 | if (pmbus_set_page(client, page) < 0) | ||
111 | break; | ||
112 | } | ||
113 | pmbus_set_page(client, 0); | ||
114 | info->pages = page; | ||
115 | } else { | ||
116 | info->pages = 1; | ||
117 | } | ||
118 | } | ||
119 | |||
120 | /* | ||
121 | * We should check if the COEFFICIENTS register is supported. | ||
122 | * If it is, and the chip is configured for direct mode, we can read | ||
123 | * the coefficients from the chip, one set per group of sensor | ||
124 | * registers. | ||
125 | * | ||
126 | * To do this, we will need access to a chip which actually supports the | ||
127 | * COEFFICIENTS command, since the command is too complex to implement | ||
128 | * without testing it. | ||
129 | */ | ||
130 | |||
131 | /* Try to find sensor groups */ | ||
132 | pmbus_find_sensor_groups(client, info); | ||
133 | |||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | static int pmbus_probe(struct i2c_client *client, | ||
138 | const struct i2c_device_id *id) | ||
139 | { | ||
140 | struct pmbus_driver_info *info; | ||
141 | int ret; | ||
142 | |||
143 | info = kzalloc(sizeof(struct pmbus_driver_info), GFP_KERNEL); | ||
144 | if (!info) | ||
145 | return -ENOMEM; | ||
146 | |||
147 | info->pages = id->driver_data; | ||
148 | info->identify = pmbus_identify; | ||
149 | |||
150 | ret = pmbus_do_probe(client, id, info); | ||
151 | if (ret < 0) | ||
152 | goto out; | ||
153 | return 0; | ||
154 | |||
155 | out: | ||
156 | kfree(info); | ||
157 | return ret; | ||
158 | } | ||
159 | |||
160 | static int pmbus_remove(struct i2c_client *client) | ||
161 | { | ||
162 | int ret; | ||
163 | const struct pmbus_driver_info *info; | ||
164 | |||
165 | info = pmbus_get_driver_info(client); | ||
166 | ret = pmbus_do_remove(client); | ||
167 | kfree(info); | ||
168 | return ret; | ||
169 | } | ||
170 | |||
171 | /* | ||
172 | * Use driver_data to set the number of pages supported by the chip. | ||
173 | */ | ||
174 | static const struct i2c_device_id pmbus_id[] = { | ||
175 | {"bmr450", 1}, | ||
176 | {"bmr451", 1}, | ||
177 | {"bmr453", 1}, | ||
178 | {"bmr454", 1}, | ||
179 | {"ltc2978", 8}, | ||
180 | {"pmbus", 0}, | ||
181 | {} | ||
182 | }; | ||
183 | |||
184 | MODULE_DEVICE_TABLE(i2c, pmbus_id); | ||
185 | |||
186 | /* This is the driver that will be inserted */ | ||
187 | static struct i2c_driver pmbus_driver = { | ||
188 | .driver = { | ||
189 | .name = "pmbus", | ||
190 | }, | ||
191 | .probe = pmbus_probe, | ||
192 | .remove = pmbus_remove, | ||
193 | .id_table = pmbus_id, | ||
194 | }; | ||
195 | |||
196 | static int __init pmbus_init(void) | ||
197 | { | ||
198 | return i2c_add_driver(&pmbus_driver); | ||
199 | } | ||
200 | |||
201 | static void __exit pmbus_exit(void) | ||
202 | { | ||
203 | i2c_del_driver(&pmbus_driver); | ||
204 | } | ||
205 | |||
206 | MODULE_AUTHOR("Guenter Roeck"); | ||
207 | MODULE_DESCRIPTION("Generic PMBus driver"); | ||
208 | MODULE_LICENSE("GPL"); | ||
209 | module_init(pmbus_init); | ||
210 | module_exit(pmbus_exit); | ||
diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h new file mode 100644 index 000000000000..50647ab7235a --- /dev/null +++ b/drivers/hwmon/pmbus/pmbus.h | |||
@@ -0,0 +1,311 @@ | |||
1 | /* | ||
2 | * pmbus.h - Common defines and structures 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 | #ifndef PMBUS_H | ||
22 | #define PMBUS_H | ||
23 | |||
24 | /* | ||
25 | * Registers | ||
26 | */ | ||
27 | #define PMBUS_PAGE 0x00 | ||
28 | #define PMBUS_OPERATION 0x01 | ||
29 | #define PMBUS_ON_OFF_CONFIG 0x02 | ||
30 | #define PMBUS_CLEAR_FAULTS 0x03 | ||
31 | #define PMBUS_PHASE 0x04 | ||
32 | |||
33 | #define PMBUS_CAPABILITY 0x19 | ||
34 | #define PMBUS_QUERY 0x1A | ||
35 | |||
36 | #define PMBUS_VOUT_MODE 0x20 | ||
37 | #define PMBUS_VOUT_COMMAND 0x21 | ||
38 | #define PMBUS_VOUT_TRIM 0x22 | ||
39 | #define PMBUS_VOUT_CAL_OFFSET 0x23 | ||
40 | #define PMBUS_VOUT_MAX 0x24 | ||
41 | #define PMBUS_VOUT_MARGIN_HIGH 0x25 | ||
42 | #define PMBUS_VOUT_MARGIN_LOW 0x26 | ||
43 | #define PMBUS_VOUT_TRANSITION_RATE 0x27 | ||
44 | #define PMBUS_VOUT_DROOP 0x28 | ||
45 | #define PMBUS_VOUT_SCALE_LOOP 0x29 | ||
46 | #define PMBUS_VOUT_SCALE_MONITOR 0x2A | ||
47 | |||
48 | #define PMBUS_COEFFICIENTS 0x30 | ||
49 | #define PMBUS_POUT_MAX 0x31 | ||
50 | |||
51 | #define PMBUS_FAN_CONFIG_12 0x3A | ||
52 | #define PMBUS_FAN_COMMAND_1 0x3B | ||
53 | #define PMBUS_FAN_COMMAND_2 0x3C | ||
54 | #define PMBUS_FAN_CONFIG_34 0x3D | ||
55 | #define PMBUS_FAN_COMMAND_3 0x3E | ||
56 | #define PMBUS_FAN_COMMAND_4 0x3F | ||
57 | |||
58 | #define PMBUS_VOUT_OV_FAULT_LIMIT 0x40 | ||
59 | #define PMBUS_VOUT_OV_FAULT_RESPONSE 0x41 | ||
60 | #define PMBUS_VOUT_OV_WARN_LIMIT 0x42 | ||
61 | #define PMBUS_VOUT_UV_WARN_LIMIT 0x43 | ||
62 | #define PMBUS_VOUT_UV_FAULT_LIMIT 0x44 | ||
63 | #define PMBUS_VOUT_UV_FAULT_RESPONSE 0x45 | ||
64 | #define PMBUS_IOUT_OC_FAULT_LIMIT 0x46 | ||
65 | #define PMBUS_IOUT_OC_FAULT_RESPONSE 0x47 | ||
66 | #define PMBUS_IOUT_OC_LV_FAULT_LIMIT 0x48 | ||
67 | #define PMBUS_IOUT_OC_LV_FAULT_RESPONSE 0x49 | ||
68 | #define PMBUS_IOUT_OC_WARN_LIMIT 0x4A | ||
69 | #define PMBUS_IOUT_UC_FAULT_LIMIT 0x4B | ||
70 | #define PMBUS_IOUT_UC_FAULT_RESPONSE 0x4C | ||
71 | |||
72 | #define PMBUS_OT_FAULT_LIMIT 0x4F | ||
73 | #define PMBUS_OT_FAULT_RESPONSE 0x50 | ||
74 | #define PMBUS_OT_WARN_LIMIT 0x51 | ||
75 | #define PMBUS_UT_WARN_LIMIT 0x52 | ||
76 | #define PMBUS_UT_FAULT_LIMIT 0x53 | ||
77 | #define PMBUS_UT_FAULT_RESPONSE 0x54 | ||
78 | #define PMBUS_VIN_OV_FAULT_LIMIT 0x55 | ||
79 | #define PMBUS_VIN_OV_FAULT_RESPONSE 0x56 | ||
80 | #define PMBUS_VIN_OV_WARN_LIMIT 0x57 | ||
81 | #define PMBUS_VIN_UV_WARN_LIMIT 0x58 | ||
82 | #define PMBUS_VIN_UV_FAULT_LIMIT 0x59 | ||
83 | |||
84 | #define PMBUS_IIN_OC_FAULT_LIMIT 0x5B | ||
85 | #define PMBUS_IIN_OC_WARN_LIMIT 0x5D | ||
86 | |||
87 | #define PMBUS_POUT_OP_FAULT_LIMIT 0x68 | ||
88 | #define PMBUS_POUT_OP_WARN_LIMIT 0x6A | ||
89 | #define PMBUS_PIN_OP_WARN_LIMIT 0x6B | ||
90 | |||
91 | #define PMBUS_STATUS_BYTE 0x78 | ||
92 | #define PMBUS_STATUS_WORD 0x79 | ||
93 | #define PMBUS_STATUS_VOUT 0x7A | ||
94 | #define PMBUS_STATUS_IOUT 0x7B | ||
95 | #define PMBUS_STATUS_INPUT 0x7C | ||
96 | #define PMBUS_STATUS_TEMPERATURE 0x7D | ||
97 | #define PMBUS_STATUS_CML 0x7E | ||
98 | #define PMBUS_STATUS_OTHER 0x7F | ||
99 | #define PMBUS_STATUS_MFR_SPECIFIC 0x80 | ||
100 | #define PMBUS_STATUS_FAN_12 0x81 | ||
101 | #define PMBUS_STATUS_FAN_34 0x82 | ||
102 | |||
103 | #define PMBUS_READ_VIN 0x88 | ||
104 | #define PMBUS_READ_IIN 0x89 | ||
105 | #define PMBUS_READ_VCAP 0x8A | ||
106 | #define PMBUS_READ_VOUT 0x8B | ||
107 | #define PMBUS_READ_IOUT 0x8C | ||
108 | #define PMBUS_READ_TEMPERATURE_1 0x8D | ||
109 | #define PMBUS_READ_TEMPERATURE_2 0x8E | ||
110 | #define PMBUS_READ_TEMPERATURE_3 0x8F | ||
111 | #define PMBUS_READ_FAN_SPEED_1 0x90 | ||
112 | #define PMBUS_READ_FAN_SPEED_2 0x91 | ||
113 | #define PMBUS_READ_FAN_SPEED_3 0x92 | ||
114 | #define PMBUS_READ_FAN_SPEED_4 0x93 | ||
115 | #define PMBUS_READ_DUTY_CYCLE 0x94 | ||
116 | #define PMBUS_READ_FREQUENCY 0x95 | ||
117 | #define PMBUS_READ_POUT 0x96 | ||
118 | #define PMBUS_READ_PIN 0x97 | ||
119 | |||
120 | #define PMBUS_REVISION 0x98 | ||
121 | #define PMBUS_MFR_ID 0x99 | ||
122 | #define PMBUS_MFR_MODEL 0x9A | ||
123 | #define PMBUS_MFR_REVISION 0x9B | ||
124 | #define PMBUS_MFR_LOCATION 0x9C | ||
125 | #define PMBUS_MFR_DATE 0x9D | ||
126 | #define PMBUS_MFR_SERIAL 0x9E | ||
127 | |||
128 | /* | ||
129 | * CAPABILITY | ||
130 | */ | ||
131 | #define PB_CAPABILITY_SMBALERT (1<<4) | ||
132 | #define PB_CAPABILITY_ERROR_CHECK (1<<7) | ||
133 | |||
134 | /* | ||
135 | * VOUT_MODE | ||
136 | */ | ||
137 | #define PB_VOUT_MODE_MODE_MASK 0xe0 | ||
138 | #define PB_VOUT_MODE_PARAM_MASK 0x1f | ||
139 | |||
140 | #define PB_VOUT_MODE_LINEAR 0x00 | ||
141 | #define PB_VOUT_MODE_VID 0x20 | ||
142 | #define PB_VOUT_MODE_DIRECT 0x40 | ||
143 | |||
144 | /* | ||
145 | * Fan configuration | ||
146 | */ | ||
147 | #define PB_FAN_2_PULSE_MASK ((1 << 0) | (1 << 1)) | ||
148 | #define PB_FAN_2_RPM (1 << 2) | ||
149 | #define PB_FAN_2_INSTALLED (1 << 3) | ||
150 | #define PB_FAN_1_PULSE_MASK ((1 << 4) | (1 << 5)) | ||
151 | #define PB_FAN_1_RPM (1 << 6) | ||
152 | #define PB_FAN_1_INSTALLED (1 << 7) | ||
153 | |||
154 | /* | ||
155 | * STATUS_BYTE, STATUS_WORD (lower) | ||
156 | */ | ||
157 | #define PB_STATUS_NONE_ABOVE (1<<0) | ||
158 | #define PB_STATUS_CML (1<<1) | ||
159 | #define PB_STATUS_TEMPERATURE (1<<2) | ||
160 | #define PB_STATUS_VIN_UV (1<<3) | ||
161 | #define PB_STATUS_IOUT_OC (1<<4) | ||
162 | #define PB_STATUS_VOUT_OV (1<<5) | ||
163 | #define PB_STATUS_OFF (1<<6) | ||
164 | #define PB_STATUS_BUSY (1<<7) | ||
165 | |||
166 | /* | ||
167 | * STATUS_WORD (upper) | ||
168 | */ | ||
169 | #define PB_STATUS_UNKNOWN (1<<8) | ||
170 | #define PB_STATUS_OTHER (1<<9) | ||
171 | #define PB_STATUS_FANS (1<<10) | ||
172 | #define PB_STATUS_POWER_GOOD_N (1<<11) | ||
173 | #define PB_STATUS_WORD_MFR (1<<12) | ||
174 | #define PB_STATUS_INPUT (1<<13) | ||
175 | #define PB_STATUS_IOUT_POUT (1<<14) | ||
176 | #define PB_STATUS_VOUT (1<<15) | ||
177 | |||
178 | /* | ||
179 | * STATUS_IOUT | ||
180 | */ | ||
181 | #define PB_POUT_OP_WARNING (1<<0) | ||
182 | #define PB_POUT_OP_FAULT (1<<1) | ||
183 | #define PB_POWER_LIMITING (1<<2) | ||
184 | #define PB_CURRENT_SHARE_FAULT (1<<3) | ||
185 | #define PB_IOUT_UC_FAULT (1<<4) | ||
186 | #define PB_IOUT_OC_WARNING (1<<5) | ||
187 | #define PB_IOUT_OC_LV_FAULT (1<<6) | ||
188 | #define PB_IOUT_OC_FAULT (1<<7) | ||
189 | |||
190 | /* | ||
191 | * STATUS_VOUT, STATUS_INPUT | ||
192 | */ | ||
193 | #define PB_VOLTAGE_UV_FAULT (1<<4) | ||
194 | #define PB_VOLTAGE_UV_WARNING (1<<5) | ||
195 | #define PB_VOLTAGE_OV_WARNING (1<<6) | ||
196 | #define PB_VOLTAGE_OV_FAULT (1<<7) | ||
197 | |||
198 | /* | ||
199 | * STATUS_INPUT | ||
200 | */ | ||
201 | #define PB_PIN_OP_WARNING (1<<0) | ||
202 | #define PB_IIN_OC_WARNING (1<<1) | ||
203 | #define PB_IIN_OC_FAULT (1<<2) | ||
204 | |||
205 | /* | ||
206 | * STATUS_TEMPERATURE | ||
207 | */ | ||
208 | #define PB_TEMP_UT_FAULT (1<<4) | ||
209 | #define PB_TEMP_UT_WARNING (1<<5) | ||
210 | #define PB_TEMP_OT_WARNING (1<<6) | ||
211 | #define PB_TEMP_OT_FAULT (1<<7) | ||
212 | |||
213 | /* | ||
214 | * STATUS_FAN | ||
215 | */ | ||
216 | #define PB_FAN_AIRFLOW_WARNING (1<<0) | ||
217 | #define PB_FAN_AIRFLOW_FAULT (1<<1) | ||
218 | #define PB_FAN_FAN2_SPEED_OVERRIDE (1<<2) | ||
219 | #define PB_FAN_FAN1_SPEED_OVERRIDE (1<<3) | ||
220 | #define PB_FAN_FAN2_WARNING (1<<4) | ||
221 | #define PB_FAN_FAN1_WARNING (1<<5) | ||
222 | #define PB_FAN_FAN2_FAULT (1<<6) | ||
223 | #define PB_FAN_FAN1_FAULT (1<<7) | ||
224 | |||
225 | /* | ||
226 | * CML_FAULT_STATUS | ||
227 | */ | ||
228 | #define PB_CML_FAULT_OTHER_MEM_LOGIC (1<<0) | ||
229 | #define PB_CML_FAULT_OTHER_COMM (1<<1) | ||
230 | #define PB_CML_FAULT_PROCESSOR (1<<3) | ||
231 | #define PB_CML_FAULT_MEMORY (1<<4) | ||
232 | #define PB_CML_FAULT_PACKET_ERROR (1<<5) | ||
233 | #define PB_CML_FAULT_INVALID_DATA (1<<6) | ||
234 | #define PB_CML_FAULT_INVALID_COMMAND (1<<7) | ||
235 | |||
236 | enum pmbus_sensor_classes { | ||
237 | PSC_VOLTAGE_IN = 0, | ||
238 | PSC_VOLTAGE_OUT, | ||
239 | PSC_CURRENT_IN, | ||
240 | PSC_CURRENT_OUT, | ||
241 | PSC_POWER, | ||
242 | PSC_TEMPERATURE, | ||
243 | PSC_FAN, | ||
244 | PSC_NUM_CLASSES /* Number of power sensor classes */ | ||
245 | }; | ||
246 | |||
247 | #define PMBUS_PAGES 32 /* Per PMBus specification */ | ||
248 | |||
249 | /* Functionality bit mask */ | ||
250 | #define PMBUS_HAVE_VIN (1 << 0) | ||
251 | #define PMBUS_HAVE_VCAP (1 << 1) | ||
252 | #define PMBUS_HAVE_VOUT (1 << 2) | ||
253 | #define PMBUS_HAVE_IIN (1 << 3) | ||
254 | #define PMBUS_HAVE_IOUT (1 << 4) | ||
255 | #define PMBUS_HAVE_PIN (1 << 5) | ||
256 | #define PMBUS_HAVE_POUT (1 << 6) | ||
257 | #define PMBUS_HAVE_FAN12 (1 << 7) | ||
258 | #define PMBUS_HAVE_FAN34 (1 << 8) | ||
259 | #define PMBUS_HAVE_TEMP (1 << 9) | ||
260 | #define PMBUS_HAVE_TEMP2 (1 << 10) | ||
261 | #define PMBUS_HAVE_TEMP3 (1 << 11) | ||
262 | #define PMBUS_HAVE_STATUS_VOUT (1 << 12) | ||
263 | #define PMBUS_HAVE_STATUS_IOUT (1 << 13) | ||
264 | #define PMBUS_HAVE_STATUS_INPUT (1 << 14) | ||
265 | #define PMBUS_HAVE_STATUS_TEMP (1 << 15) | ||
266 | #define PMBUS_HAVE_STATUS_FAN12 (1 << 16) | ||
267 | #define PMBUS_HAVE_STATUS_FAN34 (1 << 17) | ||
268 | |||
269 | struct pmbus_driver_info { | ||
270 | int pages; /* Total number of pages */ | ||
271 | bool direct[PSC_NUM_CLASSES]; | ||
272 | /* true if device uses direct data format | ||
273 | for the given sensor class */ | ||
274 | /* | ||
275 | * Support one set of coefficients for each sensor type | ||
276 | * Used for chips providing data in direct mode. | ||
277 | */ | ||
278 | int m[PSC_NUM_CLASSES]; /* mantissa for direct data format */ | ||
279 | int b[PSC_NUM_CLASSES]; /* offset */ | ||
280 | int R[PSC_NUM_CLASSES]; /* exponent */ | ||
281 | |||
282 | u32 func[PMBUS_PAGES]; /* Functionality, per page */ | ||
283 | /* | ||
284 | * The following functions map manufacturing specific register values | ||
285 | * to PMBus standard register values. Specify only if mapping is | ||
286 | * necessary. | ||
287 | */ | ||
288 | int (*read_byte_data)(struct i2c_client *client, int page, int reg); | ||
289 | /* | ||
290 | * The identify function determines supported PMBus functionality. | ||
291 | * This function is only necessary if a chip driver supports multiple | ||
292 | * chips, and the chip functionality is not pre-determined. | ||
293 | */ | ||
294 | int (*identify)(struct i2c_client *client, | ||
295 | struct pmbus_driver_info *info); | ||
296 | }; | ||
297 | |||
298 | /* Function declarations */ | ||
299 | |||
300 | int pmbus_set_page(struct i2c_client *client, u8 page); | ||
301 | int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg); | ||
302 | void pmbus_clear_faults(struct i2c_client *client); | ||
303 | bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg); | ||
304 | bool pmbus_check_word_register(struct i2c_client *client, int page, int reg); | ||
305 | int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, | ||
306 | struct pmbus_driver_info *info); | ||
307 | int pmbus_do_remove(struct i2c_client *client); | ||
308 | const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client | ||
309 | *client); | ||
310 | |||
311 | #endif /* PMBUS_H */ | ||
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c new file mode 100644 index 000000000000..8e31a8e2c746 --- /dev/null +++ b/drivers/hwmon/pmbus/pmbus_core.c | |||
@@ -0,0 +1,1567 @@ | |||
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/i2c.h> | ||
27 | #include <linux/hwmon.h> | ||
28 | #include <linux/hwmon-sysfs.h> | ||
29 | #include <linux/delay.h> | ||
30 | #include <linux/i2c/pmbus.h> | ||
31 | #include "pmbus.h" | ||
32 | |||
33 | /* | ||
34 | * Constants needed to determine number of sensors, booleans, and labels. | ||
35 | */ | ||
36 | #define PMBUS_MAX_INPUT_SENSORS 11 /* 6*volt, 3*curr, 2*power */ | ||
37 | #define PMBUS_VOUT_SENSORS_PER_PAGE 5 /* input, min, max, lcrit, | ||
38 | crit */ | ||
39 | #define PMBUS_IOUT_SENSORS_PER_PAGE 4 /* input, min, max, crit */ | ||
40 | #define PMBUS_POUT_SENSORS_PER_PAGE 4 /* input, cap, max, crit */ | ||
41 | #define PMBUS_MAX_SENSORS_PER_FAN 1 /* input */ | ||
42 | #define PMBUS_MAX_SENSORS_PER_TEMP 5 /* input, min, max, lcrit, | ||
43 | crit */ | ||
44 | |||
45 | #define PMBUS_MAX_INPUT_BOOLEANS 7 /* v: min_alarm, max_alarm, | ||
46 | lcrit_alarm, crit_alarm; | ||
47 | c: alarm, crit_alarm; | ||
48 | p: crit_alarm */ | ||
49 | #define PMBUS_VOUT_BOOLEANS_PER_PAGE 4 /* min_alarm, max_alarm, | ||
50 | lcrit_alarm, crit_alarm */ | ||
51 | #define PMBUS_IOUT_BOOLEANS_PER_PAGE 3 /* alarm, lcrit_alarm, | ||
52 | crit_alarm */ | ||
53 | #define PMBUS_POUT_BOOLEANS_PER_PAGE 2 /* alarm, crit_alarm */ | ||
54 | #define PMBUS_MAX_BOOLEANS_PER_FAN 2 /* alarm, fault */ | ||
55 | #define PMBUS_MAX_BOOLEANS_PER_TEMP 4 /* min_alarm, max_alarm, | ||
56 | lcrit_alarm, crit_alarm */ | ||
57 | |||
58 | #define PMBUS_MAX_INPUT_LABELS 4 /* vin, vcap, iin, pin */ | ||
59 | |||
60 | /* | ||
61 | * status, status_vout, status_iout, status_fans, status_fan34, and status_temp | ||
62 | * are paged. status_input is unpaged. | ||
63 | */ | ||
64 | #define PB_NUM_STATUS_REG (PMBUS_PAGES * 6 + 1) | ||
65 | |||
66 | /* | ||
67 | * Index into status register array, per status register group | ||
68 | */ | ||
69 | #define PB_STATUS_BASE 0 | ||
70 | #define PB_STATUS_VOUT_BASE (PB_STATUS_BASE + PMBUS_PAGES) | ||
71 | #define PB_STATUS_IOUT_BASE (PB_STATUS_VOUT_BASE + PMBUS_PAGES) | ||
72 | #define PB_STATUS_FAN_BASE (PB_STATUS_IOUT_BASE + PMBUS_PAGES) | ||
73 | #define PB_STATUS_FAN34_BASE (PB_STATUS_FAN_BASE + PMBUS_PAGES) | ||
74 | #define PB_STATUS_INPUT_BASE (PB_STATUS_FAN34_BASE + PMBUS_PAGES) | ||
75 | #define PB_STATUS_TEMP_BASE (PB_STATUS_INPUT_BASE + 1) | ||
76 | |||
77 | struct pmbus_sensor { | ||
78 | char name[I2C_NAME_SIZE]; /* sysfs sensor name */ | ||
79 | struct sensor_device_attribute attribute; | ||
80 | u8 page; /* page number */ | ||
81 | u8 reg; /* register */ | ||
82 | enum pmbus_sensor_classes class; /* sensor class */ | ||
83 | bool update; /* runtime sensor update needed */ | ||
84 | int data; /* Sensor data. | ||
85 | Negative if there was a read error */ | ||
86 | }; | ||
87 | |||
88 | struct pmbus_boolean { | ||
89 | char name[I2C_NAME_SIZE]; /* sysfs boolean name */ | ||
90 | struct sensor_device_attribute attribute; | ||
91 | }; | ||
92 | |||
93 | struct pmbus_label { | ||
94 | char name[I2C_NAME_SIZE]; /* sysfs label name */ | ||
95 | struct sensor_device_attribute attribute; | ||
96 | char label[I2C_NAME_SIZE]; /* label */ | ||
97 | }; | ||
98 | |||
99 | struct pmbus_data { | ||
100 | struct device *hwmon_dev; | ||
101 | |||
102 | u32 flags; /* from platform data */ | ||
103 | |||
104 | int exponent; /* linear mode: exponent for output voltages */ | ||
105 | |||
106 | const struct pmbus_driver_info *info; | ||
107 | |||
108 | int max_attributes; | ||
109 | int num_attributes; | ||
110 | struct attribute **attributes; | ||
111 | struct attribute_group group; | ||
112 | |||
113 | /* | ||
114 | * Sensors cover both sensor and limit registers. | ||
115 | */ | ||
116 | int max_sensors; | ||
117 | int num_sensors; | ||
118 | struct pmbus_sensor *sensors; | ||
119 | /* | ||
120 | * Booleans are used for alarms. | ||
121 | * Values are determined from status registers. | ||
122 | */ | ||
123 | int max_booleans; | ||
124 | int num_booleans; | ||
125 | struct pmbus_boolean *booleans; | ||
126 | /* | ||
127 | * Labels are used to map generic names (e.g., "in1") | ||
128 | * to PMBus specific names (e.g., "vin" or "vout1"). | ||
129 | */ | ||
130 | int max_labels; | ||
131 | int num_labels; | ||
132 | struct pmbus_label *labels; | ||
133 | |||
134 | struct mutex update_lock; | ||
135 | bool valid; | ||
136 | unsigned long last_updated; /* in jiffies */ | ||
137 | |||
138 | /* | ||
139 | * A single status register covers multiple attributes, | ||
140 | * so we keep them all together. | ||
141 | */ | ||
142 | u8 status[PB_NUM_STATUS_REG]; | ||
143 | |||
144 | u8 currpage; | ||
145 | }; | ||
146 | |||
147 | int pmbus_set_page(struct i2c_client *client, u8 page) | ||
148 | { | ||
149 | struct pmbus_data *data = i2c_get_clientdata(client); | ||
150 | int rv = 0; | ||
151 | int newpage; | ||
152 | |||
153 | if (page != data->currpage) { | ||
154 | rv = i2c_smbus_write_byte_data(client, PMBUS_PAGE, page); | ||
155 | newpage = i2c_smbus_read_byte_data(client, PMBUS_PAGE); | ||
156 | if (newpage != page) | ||
157 | rv = -EINVAL; | ||
158 | else | ||
159 | data->currpage = page; | ||
160 | } | ||
161 | return rv; | ||
162 | } | ||
163 | EXPORT_SYMBOL_GPL(pmbus_set_page); | ||
164 | |||
165 | static int pmbus_write_byte(struct i2c_client *client, u8 page, u8 value) | ||
166 | { | ||
167 | int rv; | ||
168 | |||
169 | rv = pmbus_set_page(client, page); | ||
170 | if (rv < 0) | ||
171 | return rv; | ||
172 | |||
173 | return i2c_smbus_write_byte(client, value); | ||
174 | } | ||
175 | |||
176 | static int pmbus_write_word_data(struct i2c_client *client, u8 page, u8 reg, | ||
177 | u16 word) | ||
178 | { | ||
179 | int rv; | ||
180 | |||
181 | rv = pmbus_set_page(client, page); | ||
182 | if (rv < 0) | ||
183 | return rv; | ||
184 | |||
185 | return i2c_smbus_write_word_data(client, reg, word); | ||
186 | } | ||
187 | |||
188 | int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg) | ||
189 | { | ||
190 | int rv; | ||
191 | |||
192 | rv = pmbus_set_page(client, page); | ||
193 | if (rv < 0) | ||
194 | return rv; | ||
195 | |||
196 | return i2c_smbus_read_word_data(client, reg); | ||
197 | } | ||
198 | EXPORT_SYMBOL_GPL(pmbus_read_word_data); | ||
199 | |||
200 | static int pmbus_read_byte_data(struct i2c_client *client, u8 page, u8 reg) | ||
201 | { | ||
202 | int rv; | ||
203 | |||
204 | rv = pmbus_set_page(client, page); | ||
205 | if (rv < 0) | ||
206 | return rv; | ||
207 | |||
208 | return i2c_smbus_read_byte_data(client, reg); | ||
209 | } | ||
210 | |||
211 | static void pmbus_clear_fault_page(struct i2c_client *client, int page) | ||
212 | { | ||
213 | pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS); | ||
214 | } | ||
215 | |||
216 | void pmbus_clear_faults(struct i2c_client *client) | ||
217 | { | ||
218 | struct pmbus_data *data = i2c_get_clientdata(client); | ||
219 | int i; | ||
220 | |||
221 | for (i = 0; i < data->info->pages; i++) | ||
222 | pmbus_clear_fault_page(client, i); | ||
223 | } | ||
224 | EXPORT_SYMBOL_GPL(pmbus_clear_faults); | ||
225 | |||
226 | static int pmbus_check_status_cml(struct i2c_client *client, int page) | ||
227 | { | ||
228 | int status, status2; | ||
229 | |||
230 | status = pmbus_read_byte_data(client, page, PMBUS_STATUS_BYTE); | ||
231 | if (status < 0 || (status & PB_STATUS_CML)) { | ||
232 | status2 = pmbus_read_byte_data(client, page, PMBUS_STATUS_CML); | ||
233 | if (status2 < 0 || (status2 & PB_CML_FAULT_INVALID_COMMAND)) | ||
234 | return -EINVAL; | ||
235 | } | ||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg) | ||
240 | { | ||
241 | int rv; | ||
242 | struct pmbus_data *data = i2c_get_clientdata(client); | ||
243 | |||
244 | rv = pmbus_read_byte_data(client, page, reg); | ||
245 | if (rv >= 0 && !(data->flags & PMBUS_SKIP_STATUS_CHECK)) | ||
246 | rv = pmbus_check_status_cml(client, page); | ||
247 | pmbus_clear_fault_page(client, page); | ||
248 | return rv >= 0; | ||
249 | } | ||
250 | EXPORT_SYMBOL_GPL(pmbus_check_byte_register); | ||
251 | |||
252 | bool pmbus_check_word_register(struct i2c_client *client, int page, int reg) | ||
253 | { | ||
254 | int rv; | ||
255 | struct pmbus_data *data = i2c_get_clientdata(client); | ||
256 | |||
257 | rv = pmbus_read_word_data(client, page, reg); | ||
258 | if (rv >= 0 && !(data->flags & PMBUS_SKIP_STATUS_CHECK)) | ||
259 | rv = pmbus_check_status_cml(client, page); | ||
260 | pmbus_clear_fault_page(client, page); | ||
261 | return rv >= 0; | ||
262 | } | ||
263 | EXPORT_SYMBOL_GPL(pmbus_check_word_register); | ||
264 | |||
265 | const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client *client) | ||
266 | { | ||
267 | struct pmbus_data *data = i2c_get_clientdata(client); | ||
268 | |||
269 | return data->info; | ||
270 | } | ||
271 | EXPORT_SYMBOL_GPL(pmbus_get_driver_info); | ||
272 | |||
273 | /* | ||
274 | * _pmbus_read_byte_data() is similar to pmbus_read_byte_data(), but checks if | ||
275 | * a device specific mapping funcion exists and calls it if necessary. | ||
276 | */ | ||
277 | static int _pmbus_read_byte_data(struct i2c_client *client, int page, int reg) | ||
278 | { | ||
279 | struct pmbus_data *data = i2c_get_clientdata(client); | ||
280 | const struct pmbus_driver_info *info = data->info; | ||
281 | int status; | ||
282 | |||
283 | if (info->read_byte_data) { | ||
284 | status = info->read_byte_data(client, page, reg); | ||
285 | if (status != -ENODATA) | ||
286 | return status; | ||
287 | } | ||
288 | return pmbus_read_byte_data(client, page, reg); | ||
289 | } | ||
290 | |||
291 | static struct pmbus_data *pmbus_update_device(struct device *dev) | ||
292 | { | ||
293 | struct i2c_client *client = to_i2c_client(dev); | ||
294 | struct pmbus_data *data = i2c_get_clientdata(client); | ||
295 | const struct pmbus_driver_info *info = data->info; | ||
296 | |||
297 | mutex_lock(&data->update_lock); | ||
298 | if (time_after(jiffies, data->last_updated + HZ) || !data->valid) { | ||
299 | int i; | ||
300 | |||
301 | for (i = 0; i < info->pages; i++) | ||
302 | data->status[PB_STATUS_BASE + i] | ||
303 | = pmbus_read_byte_data(client, i, | ||
304 | PMBUS_STATUS_BYTE); | ||
305 | for (i = 0; i < info->pages; i++) { | ||
306 | if (!(info->func[i] & PMBUS_HAVE_STATUS_VOUT)) | ||
307 | continue; | ||
308 | data->status[PB_STATUS_VOUT_BASE + i] | ||
309 | = _pmbus_read_byte_data(client, i, PMBUS_STATUS_VOUT); | ||
310 | } | ||
311 | for (i = 0; i < info->pages; i++) { | ||
312 | if (!(info->func[i] & PMBUS_HAVE_STATUS_IOUT)) | ||
313 | continue; | ||
314 | data->status[PB_STATUS_IOUT_BASE + i] | ||
315 | = _pmbus_read_byte_data(client, i, PMBUS_STATUS_IOUT); | ||
316 | } | ||
317 | for (i = 0; i < info->pages; i++) { | ||
318 | if (!(info->func[i] & PMBUS_HAVE_STATUS_TEMP)) | ||
319 | continue; | ||
320 | data->status[PB_STATUS_TEMP_BASE + i] | ||
321 | = _pmbus_read_byte_data(client, i, | ||
322 | PMBUS_STATUS_TEMPERATURE); | ||
323 | } | ||
324 | for (i = 0; i < info->pages; i++) { | ||
325 | if (!(info->func[i] & PMBUS_HAVE_STATUS_FAN12)) | ||
326 | continue; | ||
327 | data->status[PB_STATUS_FAN_BASE + i] | ||
328 | = _pmbus_read_byte_data(client, i, | ||
329 | PMBUS_STATUS_FAN_12); | ||
330 | } | ||
331 | |||
332 | for (i = 0; i < info->pages; i++) { | ||
333 | if (!(info->func[i] & PMBUS_HAVE_STATUS_FAN34)) | ||
334 | continue; | ||
335 | data->status[PB_STATUS_FAN34_BASE + i] | ||
336 | = _pmbus_read_byte_data(client, i, | ||
337 | PMBUS_STATUS_FAN_34); | ||
338 | } | ||
339 | |||
340 | if (info->func[0] & PMBUS_HAVE_STATUS_INPUT) | ||
341 | data->status[PB_STATUS_INPUT_BASE] | ||
342 | = _pmbus_read_byte_data(client, 0, | ||
343 | PMBUS_STATUS_INPUT); | ||
344 | |||
345 | for (i = 0; i < data->num_sensors; i++) { | ||
346 | struct pmbus_sensor *sensor = &data->sensors[i]; | ||
347 | |||
348 | if (!data->valid || sensor->update) | ||
349 | sensor->data | ||
350 | = pmbus_read_word_data(client, sensor->page, | ||
351 | sensor->reg); | ||
352 | } | ||
353 | pmbus_clear_faults(client); | ||
354 | data->last_updated = jiffies; | ||
355 | data->valid = 1; | ||
356 | } | ||
357 | mutex_unlock(&data->update_lock); | ||
358 | return data; | ||
359 | } | ||
360 | |||
361 | /* | ||
362 | * Convert linear sensor values to milli- or micro-units | ||
363 | * depending on sensor type. | ||
364 | */ | ||
365 | static long pmbus_reg2data_linear(struct pmbus_data *data, | ||
366 | struct pmbus_sensor *sensor) | ||
367 | { | ||
368 | s16 exponent; | ||
369 | s32 mantissa; | ||
370 | long val; | ||
371 | |||
372 | if (sensor->class == PSC_VOLTAGE_OUT) { /* LINEAR16 */ | ||
373 | exponent = data->exponent; | ||
374 | mantissa = (u16) sensor->data; | ||
375 | } else { /* LINEAR11 */ | ||
376 | exponent = (sensor->data >> 11) & 0x001f; | ||
377 | mantissa = sensor->data & 0x07ff; | ||
378 | |||
379 | if (exponent > 0x0f) | ||
380 | exponent |= 0xffe0; /* sign extend exponent */ | ||
381 | if (mantissa > 0x03ff) | ||
382 | mantissa |= 0xfffff800; /* sign extend mantissa */ | ||
383 | } | ||
384 | |||
385 | val = mantissa; | ||
386 | |||
387 | /* scale result to milli-units for all sensors except fans */ | ||
388 | if (sensor->class != PSC_FAN) | ||
389 | val = val * 1000L; | ||
390 | |||
391 | /* scale result to micro-units for power sensors */ | ||
392 | if (sensor->class == PSC_POWER) | ||
393 | val = val * 1000L; | ||
394 | |||
395 | if (exponent >= 0) | ||
396 | val <<= exponent; | ||
397 | else | ||
398 | val >>= -exponent; | ||
399 | |||
400 | return val; | ||
401 | } | ||
402 | |||
403 | /* | ||
404 | * Convert direct sensor values to milli- or micro-units | ||
405 | * depending on sensor type. | ||
406 | */ | ||
407 | static long pmbus_reg2data_direct(struct pmbus_data *data, | ||
408 | struct pmbus_sensor *sensor) | ||
409 | { | ||
410 | long val = (s16) sensor->data; | ||
411 | long m, b, R; | ||
412 | |||
413 | m = data->info->m[sensor->class]; | ||
414 | b = data->info->b[sensor->class]; | ||
415 | R = data->info->R[sensor->class]; | ||
416 | |||
417 | if (m == 0) | ||
418 | return 0; | ||
419 | |||
420 | /* X = 1/m * (Y * 10^-R - b) */ | ||
421 | R = -R; | ||
422 | /* scale result to milli-units for everything but fans */ | ||
423 | if (sensor->class != PSC_FAN) { | ||
424 | R += 3; | ||
425 | b *= 1000; | ||
426 | } | ||
427 | |||
428 | /* scale result to micro-units for power sensors */ | ||
429 | if (sensor->class == PSC_POWER) { | ||
430 | R += 3; | ||
431 | b *= 1000; | ||
432 | } | ||
433 | |||
434 | while (R > 0) { | ||
435 | val *= 10; | ||
436 | R--; | ||
437 | } | ||
438 | while (R < 0) { | ||
439 | val = DIV_ROUND_CLOSEST(val, 10); | ||
440 | R++; | ||
441 | } | ||
442 | |||
443 | return (val - b) / m; | ||
444 | } | ||
445 | |||
446 | static long pmbus_reg2data(struct pmbus_data *data, struct pmbus_sensor *sensor) | ||
447 | { | ||
448 | long val; | ||
449 | |||
450 | if (data->info->direct[sensor->class]) | ||
451 | val = pmbus_reg2data_direct(data, sensor); | ||
452 | else | ||
453 | val = pmbus_reg2data_linear(data, sensor); | ||
454 | |||
455 | return val; | ||
456 | } | ||
457 | |||
458 | #define MAX_MANTISSA (1023 * 1000) | ||
459 | #define MIN_MANTISSA (511 * 1000) | ||
460 | |||
461 | static u16 pmbus_data2reg_linear(struct pmbus_data *data, | ||
462 | enum pmbus_sensor_classes class, long val) | ||
463 | { | ||
464 | s16 exponent = 0, mantissa; | ||
465 | bool negative = false; | ||
466 | |||
467 | /* simple case */ | ||
468 | if (val == 0) | ||
469 | return 0; | ||
470 | |||
471 | if (class == PSC_VOLTAGE_OUT) { | ||
472 | /* LINEAR16 does not support negative voltages */ | ||
473 | if (val < 0) | ||
474 | return 0; | ||
475 | |||
476 | /* | ||
477 | * For a static exponents, we don't have a choice | ||
478 | * but to adjust the value to it. | ||
479 | */ | ||
480 | if (data->exponent < 0) | ||
481 | val <<= -data->exponent; | ||
482 | else | ||
483 | val >>= data->exponent; | ||
484 | val = DIV_ROUND_CLOSEST(val, 1000); | ||
485 | return val & 0xffff; | ||
486 | } | ||
487 | |||
488 | if (val < 0) { | ||
489 | negative = true; | ||
490 | val = -val; | ||
491 | } | ||
492 | |||
493 | /* Power is in uW. Convert to mW before converting. */ | ||
494 | if (class == PSC_POWER) | ||
495 | val = DIV_ROUND_CLOSEST(val, 1000L); | ||
496 | |||
497 | /* | ||
498 | * For simplicity, convert fan data to milli-units | ||
499 | * before calculating the exponent. | ||
500 | */ | ||
501 | if (class == PSC_FAN) | ||
502 | val = val * 1000; | ||
503 | |||
504 | /* Reduce large mantissa until it fits into 10 bit */ | ||
505 | while (val >= MAX_MANTISSA && exponent < 15) { | ||
506 | exponent++; | ||
507 | val >>= 1; | ||
508 | } | ||
509 | /* Increase small mantissa to improve precision */ | ||
510 | while (val < MIN_MANTISSA && exponent > -15) { | ||
511 | exponent--; | ||
512 | val <<= 1; | ||
513 | } | ||
514 | |||
515 | /* Convert mantissa from milli-units to units */ | ||
516 | mantissa = DIV_ROUND_CLOSEST(val, 1000); | ||
517 | |||
518 | /* Ensure that resulting number is within range */ | ||
519 | if (mantissa > 0x3ff) | ||
520 | mantissa = 0x3ff; | ||
521 | |||
522 | /* restore sign */ | ||
523 | if (negative) | ||
524 | mantissa = -mantissa; | ||
525 | |||
526 | /* Convert to 5 bit exponent, 11 bit mantissa */ | ||
527 | return (mantissa & 0x7ff) | ((exponent << 11) & 0xf800); | ||
528 | } | ||
529 | |||
530 | static u16 pmbus_data2reg_direct(struct pmbus_data *data, | ||
531 | enum pmbus_sensor_classes class, long val) | ||
532 | { | ||
533 | long m, b, R; | ||
534 | |||
535 | m = data->info->m[class]; | ||
536 | b = data->info->b[class]; | ||
537 | R = data->info->R[class]; | ||
538 | |||
539 | /* Power is in uW. Adjust R and b. */ | ||
540 | if (class == PSC_POWER) { | ||
541 | R -= 3; | ||
542 | b *= 1000; | ||
543 | } | ||
544 | |||
545 | /* Calculate Y = (m * X + b) * 10^R */ | ||
546 | if (class != PSC_FAN) { | ||
547 | R -= 3; /* Adjust R and b for data in milli-units */ | ||
548 | b *= 1000; | ||
549 | } | ||
550 | val = val * m + b; | ||
551 | |||
552 | while (R > 0) { | ||
553 | val *= 10; | ||
554 | R--; | ||
555 | } | ||
556 | while (R < 0) { | ||
557 | val = DIV_ROUND_CLOSEST(val, 10); | ||
558 | R++; | ||
559 | } | ||
560 | |||
561 | return val; | ||
562 | } | ||
563 | |||
564 | static u16 pmbus_data2reg(struct pmbus_data *data, | ||
565 | enum pmbus_sensor_classes class, long val) | ||
566 | { | ||
567 | u16 regval; | ||
568 | |||
569 | if (data->info->direct[class]) | ||
570 | regval = pmbus_data2reg_direct(data, class, val); | ||
571 | else | ||
572 | regval = pmbus_data2reg_linear(data, class, val); | ||
573 | |||
574 | return regval; | ||
575 | } | ||
576 | |||
577 | /* | ||
578 | * Return boolean calculated from converted data. | ||
579 | * <index> defines a status register index and mask, and optionally | ||
580 | * two sensor indexes. | ||
581 | * The upper half-word references the two sensors, | ||
582 | * two sensor indices. | ||
583 | * The upper half-word references the two optional sensors, | ||
584 | * the lower half word references status register and mask. | ||
585 | * The function returns true if (status[reg] & mask) is true and, | ||
586 | * if specified, if v1 >= v2. | ||
587 | * To determine if an object exceeds upper limits, specify <v, limit>. | ||
588 | * To determine if an object exceeds lower limits, specify <limit, v>. | ||
589 | * | ||
590 | * For booleans created with pmbus_add_boolean_reg(), only the lower 16 bits of | ||
591 | * index are set. s1 and s2 (the sensor index values) are zero in this case. | ||
592 | * The function returns true if (status[reg] & mask) is true. | ||
593 | * | ||
594 | * If the boolean was created with pmbus_add_boolean_cmp(), a comparison against | ||
595 | * a specified limit has to be performed to determine the boolean result. | ||
596 | * In this case, the function returns true if v1 >= v2 (where v1 and v2 are | ||
597 | * sensor values referenced by sensor indices s1 and s2). | ||
598 | * | ||
599 | * To determine if an object exceeds upper limits, specify <s1,s2> = <v,limit>. | ||
600 | * To determine if an object exceeds lower limits, specify <s1,s2> = <limit,v>. | ||
601 | * | ||
602 | * If a negative value is stored in any of the referenced registers, this value | ||
603 | * reflects an error code which will be returned. | ||
604 | */ | ||
605 | static int pmbus_get_boolean(struct pmbus_data *data, int index, int *val) | ||
606 | { | ||
607 | u8 s1 = (index >> 24) & 0xff; | ||
608 | u8 s2 = (index >> 16) & 0xff; | ||
609 | u8 reg = (index >> 8) & 0xff; | ||
610 | u8 mask = index & 0xff; | ||
611 | int status; | ||
612 | u8 regval; | ||
613 | |||
614 | status = data->status[reg]; | ||
615 | if (status < 0) | ||
616 | return status; | ||
617 | |||
618 | regval = status & mask; | ||
619 | if (!s1 && !s2) | ||
620 | *val = !!regval; | ||
621 | else { | ||
622 | long v1, v2; | ||
623 | struct pmbus_sensor *sensor1, *sensor2; | ||
624 | |||
625 | sensor1 = &data->sensors[s1]; | ||
626 | if (sensor1->data < 0) | ||
627 | return sensor1->data; | ||
628 | sensor2 = &data->sensors[s2]; | ||
629 | if (sensor2->data < 0) | ||
630 | return sensor2->data; | ||
631 | |||
632 | v1 = pmbus_reg2data(data, sensor1); | ||
633 | v2 = pmbus_reg2data(data, sensor2); | ||
634 | *val = !!(regval && v1 >= v2); | ||
635 | } | ||
636 | return 0; | ||
637 | } | ||
638 | |||
639 | static ssize_t pmbus_show_boolean(struct device *dev, | ||
640 | struct device_attribute *da, char *buf) | ||
641 | { | ||
642 | struct sensor_device_attribute *attr = to_sensor_dev_attr(da); | ||
643 | struct pmbus_data *data = pmbus_update_device(dev); | ||
644 | int val; | ||
645 | int err; | ||
646 | |||
647 | err = pmbus_get_boolean(data, attr->index, &val); | ||
648 | if (err) | ||
649 | return err; | ||
650 | return snprintf(buf, PAGE_SIZE, "%d\n", val); | ||
651 | } | ||
652 | |||
653 | static ssize_t pmbus_show_sensor(struct device *dev, | ||
654 | struct device_attribute *da, char *buf) | ||
655 | { | ||
656 | struct sensor_device_attribute *attr = to_sensor_dev_attr(da); | ||
657 | struct pmbus_data *data = pmbus_update_device(dev); | ||
658 | struct pmbus_sensor *sensor; | ||
659 | |||
660 | sensor = &data->sensors[attr->index]; | ||
661 | if (sensor->data < 0) | ||
662 | return sensor->data; | ||
663 | |||
664 | return snprintf(buf, PAGE_SIZE, "%ld\n", pmbus_reg2data(data, sensor)); | ||
665 | } | ||
666 | |||
667 | static ssize_t pmbus_set_sensor(struct device *dev, | ||
668 | struct device_attribute *devattr, | ||
669 | const char *buf, size_t count) | ||
670 | { | ||
671 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
672 | struct i2c_client *client = to_i2c_client(dev); | ||
673 | struct pmbus_data *data = i2c_get_clientdata(client); | ||
674 | struct pmbus_sensor *sensor = &data->sensors[attr->index]; | ||
675 | ssize_t rv = count; | ||
676 | long val = 0; | ||
677 | int ret; | ||
678 | u16 regval; | ||
679 | |||
680 | if (strict_strtol(buf, 10, &val) < 0) | ||
681 | return -EINVAL; | ||
682 | |||
683 | mutex_lock(&data->update_lock); | ||
684 | regval = pmbus_data2reg(data, sensor->class, val); | ||
685 | ret = pmbus_write_word_data(client, sensor->page, sensor->reg, regval); | ||
686 | if (ret < 0) | ||
687 | rv = ret; | ||
688 | else | ||
689 | data->sensors[attr->index].data = regval; | ||
690 | mutex_unlock(&data->update_lock); | ||
691 | return rv; | ||
692 | } | ||
693 | |||
694 | static ssize_t pmbus_show_label(struct device *dev, | ||
695 | struct device_attribute *da, char *buf) | ||
696 | { | ||
697 | struct i2c_client *client = to_i2c_client(dev); | ||
698 | struct pmbus_data *data = i2c_get_clientdata(client); | ||
699 | struct sensor_device_attribute *attr = to_sensor_dev_attr(da); | ||
700 | |||
701 | return snprintf(buf, PAGE_SIZE, "%s\n", | ||
702 | data->labels[attr->index].label); | ||
703 | } | ||
704 | |||
705 | #define PMBUS_ADD_ATTR(data, _name, _idx, _mode, _type, _show, _set) \ | ||
706 | do { \ | ||
707 | struct sensor_device_attribute *a \ | ||
708 | = &data->_type##s[data->num_##_type##s].attribute; \ | ||
709 | BUG_ON(data->num_attributes >= data->max_attributes); \ | ||
710 | sysfs_attr_init(&a->dev_attr.attr); \ | ||
711 | a->dev_attr.attr.name = _name; \ | ||
712 | a->dev_attr.attr.mode = _mode; \ | ||
713 | a->dev_attr.show = _show; \ | ||
714 | a->dev_attr.store = _set; \ | ||
715 | a->index = _idx; \ | ||
716 | data->attributes[data->num_attributes] = &a->dev_attr.attr; \ | ||
717 | data->num_attributes++; \ | ||
718 | } while (0) | ||
719 | |||
720 | #define PMBUS_ADD_GET_ATTR(data, _name, _type, _idx) \ | ||
721 | PMBUS_ADD_ATTR(data, _name, _idx, S_IRUGO, _type, \ | ||
722 | pmbus_show_##_type, NULL) | ||
723 | |||
724 | #define PMBUS_ADD_SET_ATTR(data, _name, _type, _idx) \ | ||
725 | PMBUS_ADD_ATTR(data, _name, _idx, S_IWUSR | S_IRUGO, _type, \ | ||
726 | pmbus_show_##_type, pmbus_set_##_type) | ||
727 | |||
728 | static void pmbus_add_boolean(struct pmbus_data *data, | ||
729 | const char *name, const char *type, int seq, | ||
730 | int idx) | ||
731 | { | ||
732 | struct pmbus_boolean *boolean; | ||
733 | |||
734 | BUG_ON(data->num_booleans >= data->max_booleans); | ||
735 | |||
736 | boolean = &data->booleans[data->num_booleans]; | ||
737 | |||
738 | snprintf(boolean->name, sizeof(boolean->name), "%s%d_%s", | ||
739 | name, seq, type); | ||
740 | PMBUS_ADD_GET_ATTR(data, boolean->name, boolean, idx); | ||
741 | data->num_booleans++; | ||
742 | } | ||
743 | |||
744 | static void pmbus_add_boolean_reg(struct pmbus_data *data, | ||
745 | const char *name, const char *type, | ||
746 | int seq, int reg, int bit) | ||
747 | { | ||
748 | pmbus_add_boolean(data, name, type, seq, (reg << 8) | bit); | ||
749 | } | ||
750 | |||
751 | static void pmbus_add_boolean_cmp(struct pmbus_data *data, | ||
752 | const char *name, const char *type, | ||
753 | int seq, int i1, int i2, int reg, int mask) | ||
754 | { | ||
755 | pmbus_add_boolean(data, name, type, seq, | ||
756 | (i1 << 24) | (i2 << 16) | (reg << 8) | mask); | ||
757 | } | ||
758 | |||
759 | static void pmbus_add_sensor(struct pmbus_data *data, | ||
760 | const char *name, const char *type, int seq, | ||
761 | int page, int reg, enum pmbus_sensor_classes class, | ||
762 | bool update, bool readonly) | ||
763 | { | ||
764 | struct pmbus_sensor *sensor; | ||
765 | |||
766 | BUG_ON(data->num_sensors >= data->max_sensors); | ||
767 | |||
768 | sensor = &data->sensors[data->num_sensors]; | ||
769 | snprintf(sensor->name, sizeof(sensor->name), "%s%d_%s", | ||
770 | name, seq, type); | ||
771 | sensor->page = page; | ||
772 | sensor->reg = reg; | ||
773 | sensor->class = class; | ||
774 | sensor->update = update; | ||
775 | if (readonly) | ||
776 | PMBUS_ADD_GET_ATTR(data, sensor->name, sensor, | ||
777 | data->num_sensors); | ||
778 | else | ||
779 | PMBUS_ADD_SET_ATTR(data, sensor->name, sensor, | ||
780 | data->num_sensors); | ||
781 | data->num_sensors++; | ||
782 | } | ||
783 | |||
784 | static void pmbus_add_label(struct pmbus_data *data, | ||
785 | const char *name, int seq, | ||
786 | const char *lstring, int index) | ||
787 | { | ||
788 | struct pmbus_label *label; | ||
789 | |||
790 | BUG_ON(data->num_labels >= data->max_labels); | ||
791 | |||
792 | label = &data->labels[data->num_labels]; | ||
793 | snprintf(label->name, sizeof(label->name), "%s%d_label", name, seq); | ||
794 | if (!index) | ||
795 | strncpy(label->label, lstring, sizeof(label->label) - 1); | ||
796 | else | ||
797 | snprintf(label->label, sizeof(label->label), "%s%d", lstring, | ||
798 | index); | ||
799 | |||
800 | PMBUS_ADD_GET_ATTR(data, label->name, label, data->num_labels); | ||
801 | data->num_labels++; | ||
802 | } | ||
803 | |||
804 | /* | ||
805 | * Determine maximum number of sensors, booleans, and labels. | ||
806 | * To keep things simple, only make a rough high estimate. | ||
807 | */ | ||
808 | static void pmbus_find_max_attr(struct i2c_client *client, | ||
809 | struct pmbus_data *data) | ||
810 | { | ||
811 | const struct pmbus_driver_info *info = data->info; | ||
812 | int page, max_sensors, max_booleans, max_labels; | ||
813 | |||
814 | max_sensors = PMBUS_MAX_INPUT_SENSORS; | ||
815 | max_booleans = PMBUS_MAX_INPUT_BOOLEANS; | ||
816 | max_labels = PMBUS_MAX_INPUT_LABELS; | ||
817 | |||
818 | for (page = 0; page < info->pages; page++) { | ||
819 | if (info->func[page] & PMBUS_HAVE_VOUT) { | ||
820 | max_sensors += PMBUS_VOUT_SENSORS_PER_PAGE; | ||
821 | max_booleans += PMBUS_VOUT_BOOLEANS_PER_PAGE; | ||
822 | max_labels++; | ||
823 | } | ||
824 | if (info->func[page] & PMBUS_HAVE_IOUT) { | ||
825 | max_sensors += PMBUS_IOUT_SENSORS_PER_PAGE; | ||
826 | max_booleans += PMBUS_IOUT_BOOLEANS_PER_PAGE; | ||
827 | max_labels++; | ||
828 | } | ||
829 | if (info->func[page] & PMBUS_HAVE_POUT) { | ||
830 | max_sensors += PMBUS_POUT_SENSORS_PER_PAGE; | ||
831 | max_booleans += PMBUS_POUT_BOOLEANS_PER_PAGE; | ||
832 | max_labels++; | ||
833 | } | ||
834 | if (info->func[page] & PMBUS_HAVE_FAN12) { | ||
835 | max_sensors += 2 * PMBUS_MAX_SENSORS_PER_FAN; | ||
836 | max_booleans += 2 * PMBUS_MAX_BOOLEANS_PER_FAN; | ||
837 | } | ||
838 | if (info->func[page] & PMBUS_HAVE_FAN34) { | ||
839 | max_sensors += 2 * PMBUS_MAX_SENSORS_PER_FAN; | ||
840 | max_booleans += 2 * PMBUS_MAX_BOOLEANS_PER_FAN; | ||
841 | } | ||
842 | if (info->func[page] & PMBUS_HAVE_TEMP) { | ||
843 | max_sensors += PMBUS_MAX_SENSORS_PER_TEMP; | ||
844 | max_booleans += PMBUS_MAX_BOOLEANS_PER_TEMP; | ||
845 | } | ||
846 | if (info->func[page] & PMBUS_HAVE_TEMP2) { | ||
847 | max_sensors += PMBUS_MAX_SENSORS_PER_TEMP; | ||
848 | max_booleans += PMBUS_MAX_BOOLEANS_PER_TEMP; | ||
849 | } | ||
850 | if (info->func[page] & PMBUS_HAVE_TEMP3) { | ||
851 | max_sensors += PMBUS_MAX_SENSORS_PER_TEMP; | ||
852 | max_booleans += PMBUS_MAX_BOOLEANS_PER_TEMP; | ||
853 | } | ||
854 | } | ||
855 | data->max_sensors = max_sensors; | ||
856 | data->max_booleans = max_booleans; | ||
857 | data->max_labels = max_labels; | ||
858 | data->max_attributes = max_sensors + max_booleans + max_labels; | ||
859 | } | ||
860 | |||
861 | /* | ||
862 | * Search for attributes. Allocate sensors, booleans, and labels as needed. | ||
863 | */ | ||
864 | |||
865 | /* | ||
866 | * The pmbus_limit_attr structure describes a single limit attribute | ||
867 | * and its associated alarm attribute. | ||
868 | */ | ||
869 | struct pmbus_limit_attr { | ||
870 | u8 reg; /* Limit register */ | ||
871 | const char *attr; /* Attribute name */ | ||
872 | const char *alarm; /* Alarm attribute name */ | ||
873 | u32 sbit; /* Alarm attribute status bit */ | ||
874 | }; | ||
875 | |||
876 | /* | ||
877 | * The pmbus_sensor_attr structure describes one sensor attribute. This | ||
878 | * description includes a reference to the associated limit attributes. | ||
879 | */ | ||
880 | struct pmbus_sensor_attr { | ||
881 | u8 reg; /* sensor register */ | ||
882 | enum pmbus_sensor_classes class;/* sensor class */ | ||
883 | const char *label; /* sensor label */ | ||
884 | bool paged; /* true if paged sensor */ | ||
885 | bool update; /* true if update needed */ | ||
886 | bool compare; /* true if compare function needed */ | ||
887 | u32 func; /* sensor mask */ | ||
888 | u32 sfunc; /* sensor status mask */ | ||
889 | int sbase; /* status base register */ | ||
890 | u32 gbit; /* generic status bit */ | ||
891 | const struct pmbus_limit_attr *limit;/* limit registers */ | ||
892 | int nlimit; /* # of limit registers */ | ||
893 | }; | ||
894 | |||
895 | /* | ||
896 | * Add a set of limit attributes and, if supported, the associated | ||
897 | * alarm attributes. | ||
898 | */ | ||
899 | static bool pmbus_add_limit_attrs(struct i2c_client *client, | ||
900 | struct pmbus_data *data, | ||
901 | const struct pmbus_driver_info *info, | ||
902 | const char *name, int index, int page, | ||
903 | int cbase, | ||
904 | const struct pmbus_sensor_attr *attr) | ||
905 | { | ||
906 | const struct pmbus_limit_attr *l = attr->limit; | ||
907 | int nlimit = attr->nlimit; | ||
908 | bool have_alarm = false; | ||
909 | int i, cindex; | ||
910 | |||
911 | for (i = 0; i < nlimit; i++) { | ||
912 | if (pmbus_check_word_register(client, page, l->reg)) { | ||
913 | cindex = data->num_sensors; | ||
914 | pmbus_add_sensor(data, name, l->attr, index, page, | ||
915 | l->reg, attr->class, attr->update, | ||
916 | false); | ||
917 | if (info->func[page] & attr->sfunc) { | ||
918 | if (attr->compare) { | ||
919 | pmbus_add_boolean_cmp(data, name, | ||
920 | l->alarm, index, | ||
921 | cbase, cindex, | ||
922 | attr->sbase + page, l->sbit); | ||
923 | } else { | ||
924 | pmbus_add_boolean_reg(data, name, | ||
925 | l->alarm, index, | ||
926 | attr->sbase + page, l->sbit); | ||
927 | } | ||
928 | have_alarm = true; | ||
929 | } | ||
930 | } | ||
931 | l++; | ||
932 | } | ||
933 | return have_alarm; | ||
934 | } | ||
935 | |||
936 | static void pmbus_add_sensor_attrs_one(struct i2c_client *client, | ||
937 | struct pmbus_data *data, | ||
938 | const struct pmbus_driver_info *info, | ||
939 | const char *name, | ||
940 | int index, int page, | ||
941 | const struct pmbus_sensor_attr *attr) | ||
942 | { | ||
943 | bool have_alarm; | ||
944 | int cbase = data->num_sensors; | ||
945 | |||
946 | if (attr->label) | ||
947 | pmbus_add_label(data, name, index, attr->label, | ||
948 | attr->paged ? page + 1 : 0); | ||
949 | pmbus_add_sensor(data, name, "input", index, page, attr->reg, | ||
950 | attr->class, true, true); | ||
951 | if (attr->sfunc) { | ||
952 | have_alarm = pmbus_add_limit_attrs(client, data, info, name, | ||
953 | index, page, cbase, attr); | ||
954 | /* | ||
955 | * Add generic alarm attribute only if there are no individual | ||
956 | * alarm attributes, and if there is a global alarm bit. | ||
957 | */ | ||
958 | if (!have_alarm && attr->gbit) | ||
959 | pmbus_add_boolean_reg(data, name, "alarm", index, | ||
960 | PB_STATUS_BASE + page, | ||
961 | attr->gbit); | ||
962 | } | ||
963 | } | ||
964 | |||
965 | static void pmbus_add_sensor_attrs(struct i2c_client *client, | ||
966 | struct pmbus_data *data, | ||
967 | const char *name, | ||
968 | const struct pmbus_sensor_attr *attrs, | ||
969 | int nattrs) | ||
970 | { | ||
971 | const struct pmbus_driver_info *info = data->info; | ||
972 | int index, i; | ||
973 | |||
974 | index = 1; | ||
975 | for (i = 0; i < nattrs; i++) { | ||
976 | int page, pages; | ||
977 | |||
978 | pages = attrs->paged ? info->pages : 1; | ||
979 | for (page = 0; page < pages; page++) { | ||
980 | if (!(info->func[page] & attrs->func)) | ||
981 | continue; | ||
982 | pmbus_add_sensor_attrs_one(client, data, info, name, | ||
983 | index, page, attrs); | ||
984 | index++; | ||
985 | } | ||
986 | attrs++; | ||
987 | } | ||
988 | } | ||
989 | |||
990 | static const struct pmbus_limit_attr vin_limit_attrs[] = { | ||
991 | { | ||
992 | .reg = PMBUS_VIN_UV_WARN_LIMIT, | ||
993 | .attr = "min", | ||
994 | .alarm = "min_alarm", | ||
995 | .sbit = PB_VOLTAGE_UV_WARNING, | ||
996 | }, { | ||
997 | .reg = PMBUS_VIN_UV_FAULT_LIMIT, | ||
998 | .attr = "lcrit", | ||
999 | .alarm = "lcrit_alarm", | ||
1000 | .sbit = PB_VOLTAGE_UV_FAULT, | ||
1001 | }, { | ||
1002 | .reg = PMBUS_VIN_OV_WARN_LIMIT, | ||
1003 | .attr = "max", | ||
1004 | .alarm = "max_alarm", | ||
1005 | .sbit = PB_VOLTAGE_OV_WARNING, | ||
1006 | }, { | ||
1007 | .reg = PMBUS_VIN_OV_FAULT_LIMIT, | ||
1008 | .attr = "crit", | ||
1009 | .alarm = "crit_alarm", | ||
1010 | .sbit = PB_VOLTAGE_OV_FAULT, | ||
1011 | }, | ||
1012 | }; | ||
1013 | |||
1014 | static const struct pmbus_limit_attr vout_limit_attrs[] = { | ||
1015 | { | ||
1016 | .reg = PMBUS_VOUT_UV_WARN_LIMIT, | ||
1017 | .attr = "min", | ||
1018 | .alarm = "min_alarm", | ||
1019 | .sbit = PB_VOLTAGE_UV_WARNING, | ||
1020 | }, { | ||
1021 | .reg = PMBUS_VOUT_UV_FAULT_LIMIT, | ||
1022 | .attr = "lcrit", | ||
1023 | .alarm = "lcrit_alarm", | ||
1024 | .sbit = PB_VOLTAGE_UV_FAULT, | ||
1025 | }, { | ||
1026 | .reg = PMBUS_VOUT_OV_WARN_LIMIT, | ||
1027 | .attr = "max", | ||
1028 | .alarm = "max_alarm", | ||
1029 | .sbit = PB_VOLTAGE_OV_WARNING, | ||
1030 | }, { | ||
1031 | .reg = PMBUS_VOUT_OV_FAULT_LIMIT, | ||
1032 | .attr = "crit", | ||
1033 | .alarm = "crit_alarm", | ||
1034 | .sbit = PB_VOLTAGE_OV_FAULT, | ||
1035 | } | ||
1036 | }; | ||
1037 | |||
1038 | static const struct pmbus_sensor_attr voltage_attributes[] = { | ||
1039 | { | ||
1040 | .reg = PMBUS_READ_VIN, | ||
1041 | .class = PSC_VOLTAGE_IN, | ||
1042 | .label = "vin", | ||
1043 | .func = PMBUS_HAVE_VIN, | ||
1044 | .sfunc = PMBUS_HAVE_STATUS_INPUT, | ||
1045 | .sbase = PB_STATUS_INPUT_BASE, | ||
1046 | .gbit = PB_STATUS_VIN_UV, | ||
1047 | .limit = vin_limit_attrs, | ||
1048 | .nlimit = ARRAY_SIZE(vin_limit_attrs), | ||
1049 | }, { | ||
1050 | .reg = PMBUS_READ_VCAP, | ||
1051 | .class = PSC_VOLTAGE_IN, | ||
1052 | .label = "vcap", | ||
1053 | .func = PMBUS_HAVE_VCAP, | ||
1054 | }, { | ||
1055 | .reg = PMBUS_READ_VOUT, | ||
1056 | .class = PSC_VOLTAGE_OUT, | ||
1057 | .label = "vout", | ||
1058 | .paged = true, | ||
1059 | .func = PMBUS_HAVE_VOUT, | ||
1060 | .sfunc = PMBUS_HAVE_STATUS_VOUT, | ||
1061 | .sbase = PB_STATUS_VOUT_BASE, | ||
1062 | .gbit = PB_STATUS_VOUT_OV, | ||
1063 | .limit = vout_limit_attrs, | ||
1064 | .nlimit = ARRAY_SIZE(vout_limit_attrs), | ||
1065 | } | ||
1066 | }; | ||
1067 | |||
1068 | /* Current attributes */ | ||
1069 | |||
1070 | static const struct pmbus_limit_attr iin_limit_attrs[] = { | ||
1071 | { | ||
1072 | .reg = PMBUS_IIN_OC_WARN_LIMIT, | ||
1073 | .attr = "max", | ||
1074 | .alarm = "max_alarm", | ||
1075 | .sbit = PB_IIN_OC_WARNING, | ||
1076 | }, { | ||
1077 | .reg = PMBUS_IIN_OC_FAULT_LIMIT, | ||
1078 | .attr = "crit", | ||
1079 | .alarm = "crit_alarm", | ||
1080 | .sbit = PB_IIN_OC_FAULT, | ||
1081 | } | ||
1082 | }; | ||
1083 | |||
1084 | static const struct pmbus_limit_attr iout_limit_attrs[] = { | ||
1085 | { | ||
1086 | .reg = PMBUS_IOUT_OC_WARN_LIMIT, | ||
1087 | .attr = "max", | ||
1088 | .alarm = "max_alarm", | ||
1089 | .sbit = PB_IOUT_OC_WARNING, | ||
1090 | }, { | ||
1091 | .reg = PMBUS_IOUT_UC_FAULT_LIMIT, | ||
1092 | .attr = "lcrit", | ||
1093 | .alarm = "lcrit_alarm", | ||
1094 | .sbit = PB_IOUT_UC_FAULT, | ||
1095 | }, { | ||
1096 | .reg = PMBUS_IOUT_OC_FAULT_LIMIT, | ||
1097 | .attr = "crit", | ||
1098 | .alarm = "crit_alarm", | ||
1099 | .sbit = PB_IOUT_OC_FAULT, | ||
1100 | } | ||
1101 | }; | ||
1102 | |||
1103 | static const struct pmbus_sensor_attr current_attributes[] = { | ||
1104 | { | ||
1105 | .reg = PMBUS_READ_IIN, | ||
1106 | .class = PSC_CURRENT_IN, | ||
1107 | .label = "iin", | ||
1108 | .func = PMBUS_HAVE_IIN, | ||
1109 | .sfunc = PMBUS_HAVE_STATUS_INPUT, | ||
1110 | .sbase = PB_STATUS_INPUT_BASE, | ||
1111 | .limit = iin_limit_attrs, | ||
1112 | .nlimit = ARRAY_SIZE(iin_limit_attrs), | ||
1113 | }, { | ||
1114 | .reg = PMBUS_READ_IOUT, | ||
1115 | .class = PSC_CURRENT_OUT, | ||
1116 | .label = "iout", | ||
1117 | .paged = true, | ||
1118 | .func = PMBUS_HAVE_IOUT, | ||
1119 | .sfunc = PMBUS_HAVE_STATUS_IOUT, | ||
1120 | .sbase = PB_STATUS_IOUT_BASE, | ||
1121 | .gbit = PB_STATUS_IOUT_OC, | ||
1122 | .limit = iout_limit_attrs, | ||
1123 | .nlimit = ARRAY_SIZE(iout_limit_attrs), | ||
1124 | } | ||
1125 | }; | ||
1126 | |||
1127 | /* Power attributes */ | ||
1128 | |||
1129 | static const struct pmbus_limit_attr pin_limit_attrs[] = { | ||
1130 | { | ||
1131 | .reg = PMBUS_PIN_OP_WARN_LIMIT, | ||
1132 | .attr = "max", | ||
1133 | .alarm = "alarm", | ||
1134 | .sbit = PB_PIN_OP_WARNING, | ||
1135 | } | ||
1136 | }; | ||
1137 | |||
1138 | static const struct pmbus_limit_attr pout_limit_attrs[] = { | ||
1139 | { | ||
1140 | .reg = PMBUS_POUT_MAX, | ||
1141 | .attr = "cap", | ||
1142 | .alarm = "cap_alarm", | ||
1143 | .sbit = PB_POWER_LIMITING, | ||
1144 | }, { | ||
1145 | .reg = PMBUS_POUT_OP_WARN_LIMIT, | ||
1146 | .attr = "max", | ||
1147 | .alarm = "max_alarm", | ||
1148 | .sbit = PB_POUT_OP_WARNING, | ||
1149 | }, { | ||
1150 | .reg = PMBUS_POUT_OP_FAULT_LIMIT, | ||
1151 | .attr = "crit", | ||
1152 | .alarm = "crit_alarm", | ||
1153 | .sbit = PB_POUT_OP_FAULT, | ||
1154 | } | ||
1155 | }; | ||
1156 | |||
1157 | static const struct pmbus_sensor_attr power_attributes[] = { | ||
1158 | { | ||
1159 | .reg = PMBUS_READ_PIN, | ||
1160 | .class = PSC_POWER, | ||
1161 | .label = "pin", | ||
1162 | .func = PMBUS_HAVE_PIN, | ||
1163 | .sfunc = PMBUS_HAVE_STATUS_INPUT, | ||
1164 | .sbase = PB_STATUS_INPUT_BASE, | ||
1165 | .limit = pin_limit_attrs, | ||
1166 | .nlimit = ARRAY_SIZE(pin_limit_attrs), | ||
1167 | }, { | ||
1168 | .reg = PMBUS_READ_POUT, | ||
1169 | .class = PSC_POWER, | ||
1170 | .label = "pout", | ||
1171 | .paged = true, | ||
1172 | .func = PMBUS_HAVE_POUT, | ||
1173 | .sfunc = PMBUS_HAVE_STATUS_IOUT, | ||
1174 | .sbase = PB_STATUS_IOUT_BASE, | ||
1175 | .limit = pout_limit_attrs, | ||
1176 | .nlimit = ARRAY_SIZE(pout_limit_attrs), | ||
1177 | } | ||
1178 | }; | ||
1179 | |||
1180 | /* Temperature atributes */ | ||
1181 | |||
1182 | static const struct pmbus_limit_attr temp_limit_attrs[] = { | ||
1183 | { | ||
1184 | .reg = PMBUS_UT_WARN_LIMIT, | ||
1185 | .attr = "min", | ||
1186 | .alarm = "min_alarm", | ||
1187 | .sbit = PB_TEMP_UT_WARNING, | ||
1188 | }, { | ||
1189 | .reg = PMBUS_UT_FAULT_LIMIT, | ||
1190 | .attr = "lcrit", | ||
1191 | .alarm = "lcrit_alarm", | ||
1192 | .sbit = PB_TEMP_UT_FAULT, | ||
1193 | }, { | ||
1194 | .reg = PMBUS_OT_WARN_LIMIT, | ||
1195 | .attr = "max", | ||
1196 | .alarm = "max_alarm", | ||
1197 | .sbit = PB_TEMP_OT_WARNING, | ||
1198 | }, { | ||
1199 | .reg = PMBUS_OT_FAULT_LIMIT, | ||
1200 | .attr = "crit", | ||
1201 | .alarm = "crit_alarm", | ||
1202 | .sbit = PB_TEMP_OT_FAULT, | ||
1203 | } | ||
1204 | }; | ||
1205 | |||
1206 | static const struct pmbus_sensor_attr temp_attributes[] = { | ||
1207 | { | ||
1208 | .reg = PMBUS_READ_TEMPERATURE_1, | ||
1209 | .class = PSC_TEMPERATURE, | ||
1210 | .paged = true, | ||
1211 | .update = true, | ||
1212 | .compare = true, | ||
1213 | .func = PMBUS_HAVE_TEMP, | ||
1214 | .sfunc = PMBUS_HAVE_STATUS_TEMP, | ||
1215 | .sbase = PB_STATUS_TEMP_BASE, | ||
1216 | .gbit = PB_STATUS_TEMPERATURE, | ||
1217 | .limit = temp_limit_attrs, | ||
1218 | .nlimit = ARRAY_SIZE(temp_limit_attrs), | ||
1219 | }, { | ||
1220 | .reg = PMBUS_READ_TEMPERATURE_2, | ||
1221 | .class = PSC_TEMPERATURE, | ||
1222 | .paged = true, | ||
1223 | .update = true, | ||
1224 | .compare = true, | ||
1225 | .func = PMBUS_HAVE_TEMP2, | ||
1226 | .sfunc = PMBUS_HAVE_STATUS_TEMP, | ||
1227 | .sbase = PB_STATUS_TEMP_BASE, | ||
1228 | .gbit = PB_STATUS_TEMPERATURE, | ||
1229 | .limit = temp_limit_attrs, | ||
1230 | .nlimit = ARRAY_SIZE(temp_limit_attrs), | ||
1231 | }, { | ||
1232 | .reg = PMBUS_READ_TEMPERATURE_3, | ||
1233 | .class = PSC_TEMPERATURE, | ||
1234 | .paged = true, | ||
1235 | .update = true, | ||
1236 | .compare = true, | ||
1237 | .func = PMBUS_HAVE_TEMP3, | ||
1238 | .sfunc = PMBUS_HAVE_STATUS_TEMP, | ||
1239 | .sbase = PB_STATUS_TEMP_BASE, | ||
1240 | .gbit = PB_STATUS_TEMPERATURE, | ||
1241 | .limit = temp_limit_attrs, | ||
1242 | .nlimit = ARRAY_SIZE(temp_limit_attrs), | ||
1243 | } | ||
1244 | }; | ||
1245 | |||
1246 | static const int pmbus_fan_registers[] = { | ||
1247 | PMBUS_READ_FAN_SPEED_1, | ||
1248 | PMBUS_READ_FAN_SPEED_2, | ||
1249 | PMBUS_READ_FAN_SPEED_3, | ||
1250 | PMBUS_READ_FAN_SPEED_4 | ||
1251 | }; | ||
1252 | |||
1253 | static const int pmbus_fan_config_registers[] = { | ||
1254 | PMBUS_FAN_CONFIG_12, | ||
1255 | PMBUS_FAN_CONFIG_12, | ||
1256 | PMBUS_FAN_CONFIG_34, | ||
1257 | PMBUS_FAN_CONFIG_34 | ||
1258 | }; | ||
1259 | |||
1260 | static const int pmbus_fan_status_registers[] = { | ||
1261 | PMBUS_STATUS_FAN_12, | ||
1262 | PMBUS_STATUS_FAN_12, | ||
1263 | PMBUS_STATUS_FAN_34, | ||
1264 | PMBUS_STATUS_FAN_34 | ||
1265 | }; | ||
1266 | |||
1267 | static const u32 pmbus_fan_flags[] = { | ||
1268 | PMBUS_HAVE_FAN12, | ||
1269 | PMBUS_HAVE_FAN12, | ||
1270 | PMBUS_HAVE_FAN34, | ||
1271 | PMBUS_HAVE_FAN34 | ||
1272 | }; | ||
1273 | |||
1274 | static const u32 pmbus_fan_status_flags[] = { | ||
1275 | PMBUS_HAVE_STATUS_FAN12, | ||
1276 | PMBUS_HAVE_STATUS_FAN12, | ||
1277 | PMBUS_HAVE_STATUS_FAN34, | ||
1278 | PMBUS_HAVE_STATUS_FAN34 | ||
1279 | }; | ||
1280 | |||
1281 | /* Fans */ | ||
1282 | static void pmbus_add_fan_attributes(struct i2c_client *client, | ||
1283 | struct pmbus_data *data) | ||
1284 | { | ||
1285 | const struct pmbus_driver_info *info = data->info; | ||
1286 | int index = 1; | ||
1287 | int page; | ||
1288 | |||
1289 | for (page = 0; page < info->pages; page++) { | ||
1290 | int f; | ||
1291 | |||
1292 | for (f = 0; f < ARRAY_SIZE(pmbus_fan_registers); f++) { | ||
1293 | int regval; | ||
1294 | |||
1295 | if (!(info->func[page] & pmbus_fan_flags[f])) | ||
1296 | break; | ||
1297 | |||
1298 | if (!pmbus_check_word_register(client, page, | ||
1299 | pmbus_fan_registers[f])) | ||
1300 | break; | ||
1301 | |||
1302 | /* | ||
1303 | * Skip fan if not installed. | ||
1304 | * Each fan configuration register covers multiple fans, | ||
1305 | * so we have to do some magic. | ||
1306 | */ | ||
1307 | regval = _pmbus_read_byte_data(client, page, | ||
1308 | pmbus_fan_config_registers[f]); | ||
1309 | if (regval < 0 || | ||
1310 | (!(regval & (PB_FAN_1_INSTALLED >> ((f & 1) * 4))))) | ||
1311 | continue; | ||
1312 | |||
1313 | pmbus_add_sensor(data, "fan", "input", index, page, | ||
1314 | pmbus_fan_registers[f], PSC_FAN, true, | ||
1315 | true); | ||
1316 | |||
1317 | /* | ||
1318 | * Each fan status register covers multiple fans, | ||
1319 | * so we have to do some magic. | ||
1320 | */ | ||
1321 | if ((info->func[page] & pmbus_fan_status_flags[f]) && | ||
1322 | pmbus_check_byte_register(client, | ||
1323 | page, pmbus_fan_status_registers[f])) { | ||
1324 | int base; | ||
1325 | |||
1326 | if (f > 1) /* fan 3, 4 */ | ||
1327 | base = PB_STATUS_FAN34_BASE + page; | ||
1328 | else | ||
1329 | base = PB_STATUS_FAN_BASE + page; | ||
1330 | pmbus_add_boolean_reg(data, "fan", "alarm", | ||
1331 | index, base, | ||
1332 | PB_FAN_FAN1_WARNING >> (f & 1)); | ||
1333 | pmbus_add_boolean_reg(data, "fan", "fault", | ||
1334 | index, base, | ||
1335 | PB_FAN_FAN1_FAULT >> (f & 1)); | ||
1336 | } | ||
1337 | index++; | ||
1338 | } | ||
1339 | } | ||
1340 | } | ||
1341 | |||
1342 | static void pmbus_find_attributes(struct i2c_client *client, | ||
1343 | struct pmbus_data *data) | ||
1344 | { | ||
1345 | /* Voltage sensors */ | ||
1346 | pmbus_add_sensor_attrs(client, data, "in", voltage_attributes, | ||
1347 | ARRAY_SIZE(voltage_attributes)); | ||
1348 | |||
1349 | /* Current sensors */ | ||
1350 | pmbus_add_sensor_attrs(client, data, "curr", current_attributes, | ||
1351 | ARRAY_SIZE(current_attributes)); | ||
1352 | |||
1353 | /* Power sensors */ | ||
1354 | pmbus_add_sensor_attrs(client, data, "power", power_attributes, | ||
1355 | ARRAY_SIZE(power_attributes)); | ||
1356 | |||
1357 | /* Temperature sensors */ | ||
1358 | pmbus_add_sensor_attrs(client, data, "temp", temp_attributes, | ||
1359 | ARRAY_SIZE(temp_attributes)); | ||
1360 | |||
1361 | /* Fans */ | ||
1362 | pmbus_add_fan_attributes(client, data); | ||
1363 | } | ||
1364 | |||
1365 | /* | ||
1366 | * Identify chip parameters. | ||
1367 | * This function is called for all chips. | ||
1368 | */ | ||
1369 | static int pmbus_identify_common(struct i2c_client *client, | ||
1370 | struct pmbus_data *data) | ||
1371 | { | ||
1372 | int vout_mode = -1, exponent; | ||
1373 | |||
1374 | if (pmbus_check_byte_register(client, 0, PMBUS_VOUT_MODE)) | ||
1375 | vout_mode = pmbus_read_byte_data(client, 0, PMBUS_VOUT_MODE); | ||
1376 | if (vout_mode >= 0 && vout_mode != 0xff) { | ||
1377 | /* | ||
1378 | * Not all chips support the VOUT_MODE command, | ||
1379 | * so a failure to read it is not an error. | ||
1380 | */ | ||
1381 | switch (vout_mode >> 5) { | ||
1382 | case 0: /* linear mode */ | ||
1383 | if (data->info->direct[PSC_VOLTAGE_OUT]) | ||
1384 | return -ENODEV; | ||
1385 | |||
1386 | exponent = vout_mode & 0x1f; | ||
1387 | /* and sign-extend it */ | ||
1388 | if (exponent & 0x10) | ||
1389 | exponent |= ~0x1f; | ||
1390 | data->exponent = exponent; | ||
1391 | break; | ||
1392 | case 2: /* direct mode */ | ||
1393 | if (!data->info->direct[PSC_VOLTAGE_OUT]) | ||
1394 | return -ENODEV; | ||
1395 | break; | ||
1396 | default: | ||
1397 | return -ENODEV; | ||
1398 | } | ||
1399 | } | ||
1400 | |||
1401 | /* Determine maximum number of sensors, booleans, and labels */ | ||
1402 | pmbus_find_max_attr(client, data); | ||
1403 | pmbus_clear_fault_page(client, 0); | ||
1404 | return 0; | ||
1405 | } | ||
1406 | |||
1407 | int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id, | ||
1408 | struct pmbus_driver_info *info) | ||
1409 | { | ||
1410 | const struct pmbus_platform_data *pdata = client->dev.platform_data; | ||
1411 | struct pmbus_data *data; | ||
1412 | int ret; | ||
1413 | |||
1414 | if (!info) { | ||
1415 | dev_err(&client->dev, "Missing chip information"); | ||
1416 | return -ENODEV; | ||
1417 | } | ||
1418 | |||
1419 | if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE | ||
1420 | | I2C_FUNC_SMBUS_BYTE_DATA | ||
1421 | | I2C_FUNC_SMBUS_WORD_DATA)) | ||
1422 | return -ENODEV; | ||
1423 | |||
1424 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
1425 | if (!data) { | ||
1426 | dev_err(&client->dev, "No memory to allocate driver data\n"); | ||
1427 | return -ENOMEM; | ||
1428 | } | ||
1429 | |||
1430 | i2c_set_clientdata(client, data); | ||
1431 | mutex_init(&data->update_lock); | ||
1432 | |||
1433 | /* Bail out if PMBus status register does not exist. */ | ||
1434 | if (i2c_smbus_read_byte_data(client, PMBUS_STATUS_BYTE) < 0) { | ||
1435 | dev_err(&client->dev, "PMBus status register not found\n"); | ||
1436 | ret = -ENODEV; | ||
1437 | goto out_data; | ||
1438 | } | ||
1439 | |||
1440 | if (pdata) | ||
1441 | data->flags = pdata->flags; | ||
1442 | data->info = info; | ||
1443 | |||
1444 | pmbus_clear_faults(client); | ||
1445 | |||
1446 | if (info->identify) { | ||
1447 | ret = (*info->identify)(client, info); | ||
1448 | if (ret < 0) { | ||
1449 | dev_err(&client->dev, "Chip identification failed\n"); | ||
1450 | goto out_data; | ||
1451 | } | ||
1452 | } | ||
1453 | |||
1454 | if (info->pages <= 0 || info->pages > PMBUS_PAGES) { | ||
1455 | dev_err(&client->dev, "Bad number of PMBus pages: %d\n", | ||
1456 | info->pages); | ||
1457 | ret = -EINVAL; | ||
1458 | goto out_data; | ||
1459 | } | ||
1460 | /* | ||
1461 | * Bail out if more than one page was configured, but we can not | ||
1462 | * select the highest page. This is an indication that the wrong | ||
1463 | * chip type was selected. Better bail out now than keep | ||
1464 | * returning errors later on. | ||
1465 | */ | ||
1466 | if (info->pages > 1 && pmbus_set_page(client, info->pages - 1) < 0) { | ||
1467 | dev_err(&client->dev, "Failed to select page %d\n", | ||
1468 | info->pages - 1); | ||
1469 | ret = -EINVAL; | ||
1470 | goto out_data; | ||
1471 | } | ||
1472 | |||
1473 | ret = pmbus_identify_common(client, data); | ||
1474 | if (ret < 0) { | ||
1475 | dev_err(&client->dev, "Failed to identify chip capabilities\n"); | ||
1476 | goto out_data; | ||
1477 | } | ||
1478 | |||
1479 | ret = -ENOMEM; | ||
1480 | data->sensors = kzalloc(sizeof(struct pmbus_sensor) * data->max_sensors, | ||
1481 | GFP_KERNEL); | ||
1482 | if (!data->sensors) { | ||
1483 | dev_err(&client->dev, "No memory to allocate sensor data\n"); | ||
1484 | goto out_data; | ||
1485 | } | ||
1486 | |||
1487 | data->booleans = kzalloc(sizeof(struct pmbus_boolean) | ||
1488 | * data->max_booleans, GFP_KERNEL); | ||
1489 | if (!data->booleans) { | ||
1490 | dev_err(&client->dev, "No memory to allocate boolean data\n"); | ||
1491 | goto out_sensors; | ||
1492 | } | ||
1493 | |||
1494 | data->labels = kzalloc(sizeof(struct pmbus_label) * data->max_labels, | ||
1495 | GFP_KERNEL); | ||
1496 | if (!data->labels) { | ||
1497 | dev_err(&client->dev, "No memory to allocate label data\n"); | ||
1498 | goto out_booleans; | ||
1499 | } | ||
1500 | |||
1501 | data->attributes = kzalloc(sizeof(struct attribute *) | ||
1502 | * data->max_attributes, GFP_KERNEL); | ||
1503 | if (!data->attributes) { | ||
1504 | dev_err(&client->dev, "No memory to allocate attribute data\n"); | ||
1505 | goto out_labels; | ||
1506 | } | ||
1507 | |||
1508 | pmbus_find_attributes(client, data); | ||
1509 | |||
1510 | /* | ||
1511 | * If there are no attributes, something is wrong. | ||
1512 | * Bail out instead of trying to register nothing. | ||
1513 | */ | ||
1514 | if (!data->num_attributes) { | ||
1515 | dev_err(&client->dev, "No attributes found\n"); | ||
1516 | ret = -ENODEV; | ||
1517 | goto out_attributes; | ||
1518 | } | ||
1519 | |||
1520 | /* Register sysfs hooks */ | ||
1521 | data->group.attrs = data->attributes; | ||
1522 | ret = sysfs_create_group(&client->dev.kobj, &data->group); | ||
1523 | if (ret) { | ||
1524 | dev_err(&client->dev, "Failed to create sysfs entries\n"); | ||
1525 | goto out_attributes; | ||
1526 | } | ||
1527 | data->hwmon_dev = hwmon_device_register(&client->dev); | ||
1528 | if (IS_ERR(data->hwmon_dev)) { | ||
1529 | ret = PTR_ERR(data->hwmon_dev); | ||
1530 | dev_err(&client->dev, "Failed to register hwmon device\n"); | ||
1531 | goto out_hwmon_device_register; | ||
1532 | } | ||
1533 | return 0; | ||
1534 | |||
1535 | out_hwmon_device_register: | ||
1536 | sysfs_remove_group(&client->dev.kobj, &data->group); | ||
1537 | out_attributes: | ||
1538 | kfree(data->attributes); | ||
1539 | out_labels: | ||
1540 | kfree(data->labels); | ||
1541 | out_booleans: | ||
1542 | kfree(data->booleans); | ||
1543 | out_sensors: | ||
1544 | kfree(data->sensors); | ||
1545 | out_data: | ||
1546 | kfree(data); | ||
1547 | return ret; | ||
1548 | } | ||
1549 | EXPORT_SYMBOL_GPL(pmbus_do_probe); | ||
1550 | |||
1551 | int pmbus_do_remove(struct i2c_client *client) | ||
1552 | { | ||
1553 | struct pmbus_data *data = i2c_get_clientdata(client); | ||
1554 | hwmon_device_unregister(data->hwmon_dev); | ||
1555 | sysfs_remove_group(&client->dev.kobj, &data->group); | ||
1556 | kfree(data->attributes); | ||
1557 | kfree(data->labels); | ||
1558 | kfree(data->booleans); | ||
1559 | kfree(data->sensors); | ||
1560 | kfree(data); | ||
1561 | return 0; | ||
1562 | } | ||
1563 | EXPORT_SYMBOL_GPL(pmbus_do_remove); | ||
1564 | |||
1565 | MODULE_AUTHOR("Guenter Roeck"); | ||
1566 | MODULE_DESCRIPTION("PMBus core driver"); | ||
1567 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/hwmon/pmbus/ucd9000.c b/drivers/hwmon/pmbus/ucd9000.c new file mode 100644 index 000000000000..ace1c7319734 --- /dev/null +++ b/drivers/hwmon/pmbus/ucd9000.c | |||
@@ -0,0 +1,278 @@ | |||
1 | /* | ||
2 | * Hardware monitoring driver for UCD90xxx Sequencer and System Health | ||
3 | * Controller series | ||
4 | * | ||
5 | * Copyright (C) 2011 Ericsson AB. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/err.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/i2c.h> | ||
28 | #include <linux/i2c/pmbus.h> | ||
29 | #include "pmbus.h" | ||
30 | |||
31 | enum chips { ucd9000, ucd90120, ucd90124, ucd9090, ucd90910 }; | ||
32 | |||
33 | #define UCD9000_MONITOR_CONFIG 0xd5 | ||
34 | #define UCD9000_NUM_PAGES 0xd6 | ||
35 | #define UCD9000_FAN_CONFIG_INDEX 0xe7 | ||
36 | #define UCD9000_FAN_CONFIG 0xe8 | ||
37 | #define UCD9000_DEVICE_ID 0xfd | ||
38 | |||
39 | #define UCD9000_MON_TYPE(x) (((x) >> 5) & 0x07) | ||
40 | #define UCD9000_MON_PAGE(x) ((x) & 0x0f) | ||
41 | |||
42 | #define UCD9000_MON_VOLTAGE 1 | ||
43 | #define UCD9000_MON_TEMPERATURE 2 | ||
44 | #define UCD9000_MON_CURRENT 3 | ||
45 | #define UCD9000_MON_VOLTAGE_HW 4 | ||
46 | |||
47 | #define UCD9000_NUM_FAN 4 | ||
48 | |||
49 | struct ucd9000_data { | ||
50 | u8 fan_data[UCD9000_NUM_FAN][I2C_SMBUS_BLOCK_MAX]; | ||
51 | struct pmbus_driver_info info; | ||
52 | }; | ||
53 | #define to_ucd9000_data(_info) container_of(_info, struct ucd9000_data, info) | ||
54 | |||
55 | static int ucd9000_get_fan_config(struct i2c_client *client, int fan) | ||
56 | { | ||
57 | int fan_config = 0; | ||
58 | struct ucd9000_data *data | ||
59 | = to_ucd9000_data(pmbus_get_driver_info(client)); | ||
60 | |||
61 | if (data->fan_data[fan][3] & 1) | ||
62 | fan_config |= PB_FAN_2_INSTALLED; /* Use lower bit position */ | ||
63 | |||
64 | /* Pulses/revolution */ | ||
65 | fan_config |= (data->fan_data[fan][3] & 0x06) >> 1; | ||
66 | |||
67 | return fan_config; | ||
68 | } | ||
69 | |||
70 | static int ucd9000_read_byte_data(struct i2c_client *client, int page, int reg) | ||
71 | { | ||
72 | int ret = 0; | ||
73 | int fan_config; | ||
74 | |||
75 | switch (reg) { | ||
76 | case PMBUS_FAN_CONFIG_12: | ||
77 | if (page) | ||
78 | return -EINVAL; | ||
79 | |||
80 | ret = ucd9000_get_fan_config(client, 0); | ||
81 | if (ret < 0) | ||
82 | return ret; | ||
83 | fan_config = ret << 4; | ||
84 | ret = ucd9000_get_fan_config(client, 1); | ||
85 | if (ret < 0) | ||
86 | return ret; | ||
87 | fan_config |= ret; | ||
88 | ret = fan_config; | ||
89 | break; | ||
90 | case PMBUS_FAN_CONFIG_34: | ||
91 | if (page) | ||
92 | return -EINVAL; | ||
93 | |||
94 | ret = ucd9000_get_fan_config(client, 2); | ||
95 | if (ret < 0) | ||
96 | return ret; | ||
97 | fan_config = ret << 4; | ||
98 | ret = ucd9000_get_fan_config(client, 3); | ||
99 | if (ret < 0) | ||
100 | return ret; | ||
101 | fan_config |= ret; | ||
102 | ret = fan_config; | ||
103 | break; | ||
104 | default: | ||
105 | ret = -ENODATA; | ||
106 | break; | ||
107 | } | ||
108 | return ret; | ||
109 | } | ||
110 | |||
111 | static const struct i2c_device_id ucd9000_id[] = { | ||
112 | {"ucd9000", ucd9000}, | ||
113 | {"ucd90120", ucd90120}, | ||
114 | {"ucd90124", ucd90124}, | ||
115 | {"ucd9090", ucd9090}, | ||
116 | {"ucd90910", ucd90910}, | ||
117 | {} | ||
118 | }; | ||
119 | MODULE_DEVICE_TABLE(i2c, ucd9000_id); | ||
120 | |||
121 | static int ucd9000_probe(struct i2c_client *client, | ||
122 | const struct i2c_device_id *id) | ||
123 | { | ||
124 | u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1]; | ||
125 | struct ucd9000_data *data; | ||
126 | struct pmbus_driver_info *info; | ||
127 | const struct i2c_device_id *mid; | ||
128 | int i, ret; | ||
129 | |||
130 | if (!i2c_check_functionality(client->adapter, | ||
131 | I2C_FUNC_SMBUS_BYTE_DATA | | ||
132 | I2C_FUNC_SMBUS_BLOCK_DATA)) | ||
133 | return -ENODEV; | ||
134 | |||
135 | ret = i2c_smbus_read_block_data(client, UCD9000_DEVICE_ID, | ||
136 | block_buffer); | ||
137 | if (ret < 0) { | ||
138 | dev_err(&client->dev, "Failed to read device ID\n"); | ||
139 | return ret; | ||
140 | } | ||
141 | block_buffer[ret] = '\0'; | ||
142 | dev_info(&client->dev, "Device ID %s\n", block_buffer); | ||
143 | |||
144 | mid = NULL; | ||
145 | for (i = 0; i < ARRAY_SIZE(ucd9000_id); i++) { | ||
146 | mid = &ucd9000_id[i]; | ||
147 | if (!strncasecmp(mid->name, block_buffer, strlen(mid->name))) | ||
148 | break; | ||
149 | } | ||
150 | if (!mid || !strlen(mid->name)) { | ||
151 | dev_err(&client->dev, "Unsupported device\n"); | ||
152 | return -ENODEV; | ||
153 | } | ||
154 | |||
155 | if (id->driver_data != ucd9000 && id->driver_data != mid->driver_data) | ||
156 | dev_notice(&client->dev, | ||
157 | "Device mismatch: Configured %s, detected %s\n", | ||
158 | id->name, mid->name); | ||
159 | |||
160 | data = kzalloc(sizeof(struct ucd9000_data), GFP_KERNEL); | ||
161 | if (!data) | ||
162 | return -ENOMEM; | ||
163 | info = &data->info; | ||
164 | |||
165 | ret = i2c_smbus_read_byte_data(client, UCD9000_NUM_PAGES); | ||
166 | if (ret < 0) { | ||
167 | dev_err(&client->dev, | ||
168 | "Failed to read number of active pages\n"); | ||
169 | goto out; | ||
170 | } | ||
171 | info->pages = ret; | ||
172 | if (!info->pages) { | ||
173 | dev_err(&client->dev, "No pages configured\n"); | ||
174 | ret = -ENODEV; | ||
175 | goto out; | ||
176 | } | ||
177 | |||
178 | /* The internal temperature sensor is always active */ | ||
179 | info->func[0] = PMBUS_HAVE_TEMP; | ||
180 | |||
181 | /* Everything else is configurable */ | ||
182 | ret = i2c_smbus_read_block_data(client, UCD9000_MONITOR_CONFIG, | ||
183 | block_buffer); | ||
184 | if (ret <= 0) { | ||
185 | dev_err(&client->dev, "Failed to read configuration data\n"); | ||
186 | ret = -ENODEV; | ||
187 | goto out; | ||
188 | } | ||
189 | for (i = 0; i < ret; i++) { | ||
190 | int page = UCD9000_MON_PAGE(block_buffer[i]); | ||
191 | |||
192 | if (page >= info->pages) | ||
193 | continue; | ||
194 | |||
195 | switch (UCD9000_MON_TYPE(block_buffer[i])) { | ||
196 | case UCD9000_MON_VOLTAGE: | ||
197 | case UCD9000_MON_VOLTAGE_HW: | ||
198 | info->func[page] |= PMBUS_HAVE_VOUT | ||
199 | | PMBUS_HAVE_STATUS_VOUT; | ||
200 | break; | ||
201 | case UCD9000_MON_TEMPERATURE: | ||
202 | info->func[page] |= PMBUS_HAVE_TEMP2 | ||
203 | | PMBUS_HAVE_STATUS_TEMP; | ||
204 | break; | ||
205 | case UCD9000_MON_CURRENT: | ||
206 | info->func[page] |= PMBUS_HAVE_IOUT | ||
207 | | PMBUS_HAVE_STATUS_IOUT; | ||
208 | break; | ||
209 | default: | ||
210 | break; | ||
211 | } | ||
212 | } | ||
213 | |||
214 | /* Fan configuration */ | ||
215 | if (mid->driver_data == ucd90124) { | ||
216 | for (i = 0; i < UCD9000_NUM_FAN; i++) { | ||
217 | i2c_smbus_write_byte_data(client, | ||
218 | UCD9000_FAN_CONFIG_INDEX, i); | ||
219 | ret = i2c_smbus_read_block_data(client, | ||
220 | UCD9000_FAN_CONFIG, | ||
221 | data->fan_data[i]); | ||
222 | if (ret < 0) | ||
223 | goto out; | ||
224 | } | ||
225 | i2c_smbus_write_byte_data(client, UCD9000_FAN_CONFIG_INDEX, 0); | ||
226 | |||
227 | info->read_byte_data = ucd9000_read_byte_data; | ||
228 | info->func[0] |= PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12 | ||
229 | | PMBUS_HAVE_FAN34 | PMBUS_HAVE_STATUS_FAN34; | ||
230 | } | ||
231 | |||
232 | ret = pmbus_do_probe(client, mid, info); | ||
233 | if (ret < 0) | ||
234 | goto out; | ||
235 | return 0; | ||
236 | |||
237 | out: | ||
238 | kfree(data); | ||
239 | return ret; | ||
240 | } | ||
241 | |||
242 | static int ucd9000_remove(struct i2c_client *client) | ||
243 | { | ||
244 | int ret; | ||
245 | struct ucd9000_data *data; | ||
246 | |||
247 | data = to_ucd9000_data(pmbus_get_driver_info(client)); | ||
248 | ret = pmbus_do_remove(client); | ||
249 | kfree(data); | ||
250 | return ret; | ||
251 | } | ||
252 | |||
253 | |||
254 | /* This is the driver that will be inserted */ | ||
255 | static struct i2c_driver ucd9000_driver = { | ||
256 | .driver = { | ||
257 | .name = "ucd9000", | ||
258 | }, | ||
259 | .probe = ucd9000_probe, | ||
260 | .remove = ucd9000_remove, | ||
261 | .id_table = ucd9000_id, | ||
262 | }; | ||
263 | |||
264 | static int __init ucd9000_init(void) | ||
265 | { | ||
266 | return i2c_add_driver(&ucd9000_driver); | ||
267 | } | ||
268 | |||
269 | static void __exit ucd9000_exit(void) | ||
270 | { | ||
271 | i2c_del_driver(&ucd9000_driver); | ||
272 | } | ||
273 | |||
274 | MODULE_AUTHOR("Guenter Roeck"); | ||
275 | MODULE_DESCRIPTION("PMBus driver for TI UCD90xxx"); | ||
276 | MODULE_LICENSE("GPL"); | ||
277 | module_init(ucd9000_init); | ||
278 | module_exit(ucd9000_exit); | ||
diff --git a/drivers/hwmon/pmbus/ucd9200.c b/drivers/hwmon/pmbus/ucd9200.c new file mode 100644 index 000000000000..ffcc1cf3609d --- /dev/null +++ b/drivers/hwmon/pmbus/ucd9200.c | |||
@@ -0,0 +1,210 @@ | |||
1 | /* | ||
2 | * Hardware monitoring driver for ucd9200 series Digital PWM System Controllers | ||
3 | * | ||
4 | * Copyright (C) 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/i2c.h> | ||
27 | #include <linux/i2c/pmbus.h> | ||
28 | #include "pmbus.h" | ||
29 | |||
30 | #define UCD9200_PHASE_INFO 0xd2 | ||
31 | #define UCD9200_DEVICE_ID 0xfd | ||
32 | |||
33 | enum chips { ucd9200, ucd9220, ucd9222, ucd9224, ucd9240, ucd9244, ucd9246, | ||
34 | ucd9248 }; | ||
35 | |||
36 | static const struct i2c_device_id ucd9200_id[] = { | ||
37 | {"ucd9200", ucd9200}, | ||
38 | {"ucd9220", ucd9220}, | ||
39 | {"ucd9222", ucd9222}, | ||
40 | {"ucd9224", ucd9224}, | ||
41 | {"ucd9240", ucd9240}, | ||
42 | {"ucd9244", ucd9244}, | ||
43 | {"ucd9246", ucd9246}, | ||
44 | {"ucd9248", ucd9248}, | ||
45 | {} | ||
46 | }; | ||
47 | MODULE_DEVICE_TABLE(i2c, ucd9200_id); | ||
48 | |||
49 | static int ucd9200_probe(struct i2c_client *client, | ||
50 | const struct i2c_device_id *id) | ||
51 | { | ||
52 | u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1]; | ||
53 | struct pmbus_driver_info *info; | ||
54 | const struct i2c_device_id *mid; | ||
55 | int i, j, ret; | ||
56 | |||
57 | if (!i2c_check_functionality(client->adapter, | ||
58 | I2C_FUNC_SMBUS_BYTE_DATA | | ||
59 | I2C_FUNC_SMBUS_BLOCK_DATA)) | ||
60 | return -ENODEV; | ||
61 | |||
62 | ret = i2c_smbus_read_block_data(client, UCD9200_DEVICE_ID, | ||
63 | block_buffer); | ||
64 | if (ret < 0) { | ||
65 | dev_err(&client->dev, "Failed to read device ID\n"); | ||
66 | return ret; | ||
67 | } | ||
68 | block_buffer[ret] = '\0'; | ||
69 | dev_info(&client->dev, "Device ID %s\n", block_buffer); | ||
70 | |||
71 | mid = NULL; | ||
72 | for (i = 0; i < ARRAY_SIZE(ucd9200_id); i++) { | ||
73 | mid = &ucd9200_id[i]; | ||
74 | if (!strncasecmp(mid->name, block_buffer, strlen(mid->name))) | ||
75 | break; | ||
76 | } | ||
77 | if (!mid || !strlen(mid->name)) { | ||
78 | dev_err(&client->dev, "Unsupported device\n"); | ||
79 | return -ENODEV; | ||
80 | } | ||
81 | if (id->driver_data != ucd9200 && id->driver_data != mid->driver_data) | ||
82 | dev_notice(&client->dev, | ||
83 | "Device mismatch: Configured %s, detected %s\n", | ||
84 | id->name, mid->name); | ||
85 | |||
86 | info = kzalloc(sizeof(struct pmbus_driver_info), GFP_KERNEL); | ||
87 | if (!info) | ||
88 | return -ENOMEM; | ||
89 | |||
90 | ret = i2c_smbus_read_block_data(client, UCD9200_PHASE_INFO, | ||
91 | block_buffer); | ||
92 | if (ret < 0) { | ||
93 | dev_err(&client->dev, "Failed to read phase information\n"); | ||
94 | goto out; | ||
95 | } | ||
96 | |||
97 | /* | ||
98 | * Calculate number of configured pages (rails) from PHASE_INFO | ||
99 | * register. | ||
100 | * Rails have to be sequential, so we can abort after finding | ||
101 | * the first unconfigured rail. | ||
102 | */ | ||
103 | info->pages = 0; | ||
104 | for (i = 0; i < ret; i++) { | ||
105 | if (!block_buffer[i]) | ||
106 | break; | ||
107 | info->pages++; | ||
108 | } | ||
109 | if (!info->pages) { | ||
110 | dev_err(&client->dev, "No rails configured\n"); | ||
111 | ret = -ENODEV; | ||
112 | goto out; | ||
113 | } | ||
114 | dev_info(&client->dev, "%d rails configured\n", info->pages); | ||
115 | |||
116 | /* | ||
117 | * Set PHASE registers on all pages to 0xff to ensure that phase | ||
118 | * specific commands will apply to all phases of a given page (rail). | ||
119 | * This only affects the READ_IOUT and READ_TEMPERATURE2 registers. | ||
120 | * READ_IOUT will return the sum of currents of all phases of a rail, | ||
121 | * and READ_TEMPERATURE2 will return the maximum temperature detected | ||
122 | * for the the phases of the rail. | ||
123 | */ | ||
124 | for (i = 0; i < info->pages; i++) { | ||
125 | /* | ||
126 | * Setting PAGE & PHASE fails once in a while for no obvious | ||
127 | * reason, so we need to retry a couple of times. | ||
128 | */ | ||
129 | for (j = 0; j < 3; j++) { | ||
130 | ret = i2c_smbus_write_byte_data(client, PMBUS_PAGE, i); | ||
131 | if (ret < 0) | ||
132 | continue; | ||
133 | ret = i2c_smbus_write_byte_data(client, PMBUS_PHASE, | ||
134 | 0xff); | ||
135 | if (ret < 0) | ||
136 | continue; | ||
137 | break; | ||
138 | } | ||
139 | if (ret < 0) { | ||
140 | dev_err(&client->dev, | ||
141 | "Failed to initialize PHASE registers\n"); | ||
142 | goto out; | ||
143 | } | ||
144 | } | ||
145 | if (info->pages > 1) | ||
146 | i2c_smbus_write_byte_data(client, PMBUS_PAGE, 0); | ||
147 | |||
148 | info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT | | ||
149 | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN | | ||
150 | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | | ||
151 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | | ||
152 | PMBUS_HAVE_POUT | PMBUS_HAVE_TEMP | | ||
153 | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP; | ||
154 | |||
155 | for (i = 1; i < info->pages; i++) | ||
156 | info->func[i] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | | ||
157 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | | ||
158 | PMBUS_HAVE_POUT | | ||
159 | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP; | ||
160 | |||
161 | /* ucd9240 supports a single fan */ | ||
162 | if (mid->driver_data == ucd9240) | ||
163 | info->func[0] |= PMBUS_HAVE_FAN12 | PMBUS_HAVE_STATUS_FAN12; | ||
164 | |||
165 | ret = pmbus_do_probe(client, mid, info); | ||
166 | if (ret < 0) | ||
167 | goto out; | ||
168 | return 0; | ||
169 | out: | ||
170 | kfree(info); | ||
171 | return ret; | ||
172 | } | ||
173 | |||
174 | static int ucd9200_remove(struct i2c_client *client) | ||
175 | { | ||
176 | int ret; | ||
177 | const struct pmbus_driver_info *info; | ||
178 | |||
179 | info = pmbus_get_driver_info(client); | ||
180 | ret = pmbus_do_remove(client); | ||
181 | kfree(info); | ||
182 | return ret; | ||
183 | } | ||
184 | |||
185 | |||
186 | /* This is the driver that will be inserted */ | ||
187 | static struct i2c_driver ucd9200_driver = { | ||
188 | .driver = { | ||
189 | .name = "ucd9200", | ||
190 | }, | ||
191 | .probe = ucd9200_probe, | ||
192 | .remove = ucd9200_remove, | ||
193 | .id_table = ucd9200_id, | ||
194 | }; | ||
195 | |||
196 | static int __init ucd9200_init(void) | ||
197 | { | ||
198 | return i2c_add_driver(&ucd9200_driver); | ||
199 | } | ||
200 | |||
201 | static void __exit ucd9200_exit(void) | ||
202 | { | ||
203 | i2c_del_driver(&ucd9200_driver); | ||
204 | } | ||
205 | |||
206 | MODULE_AUTHOR("Guenter Roeck"); | ||
207 | MODULE_DESCRIPTION("PMBus driver for TI UCD922x, UCD924x"); | ||
208 | MODULE_LICENSE("GPL"); | ||
209 | module_init(ucd9200_init); | ||
210 | module_exit(ucd9200_exit); | ||