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