diff options
author | Maxim Sloyko <maxims@google.com> | 2019-04-15 18:28:07 -0400 |
---|---|---|
committer | Guenter Roeck <linux@roeck-us.net> | 2019-04-15 20:19:53 -0400 |
commit | 038a9c3d1e42420943c60f879fdb00b62f207f9c (patch) | |
tree | d7f5e84bd3bbb79c8038f2ac47f445281415b062 | |
parent | 991d679951f0df27db170036080746b84115e1e7 (diff) |
hwmon: (pmbus/isl68137) Add driver for Intersil ISL68137 PWM Controller
Intersil ISL68137 is a digital output 7-phase configurable PWM
controller with an AVSBus interface.
Signed-off-by: Maxim Sloyko <maxims@google.com>
Signed-off-by: Robert Lippert <rlippert@google.com>
Signed-off-by: Patrick Venture <venture@google.com>
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
-rw-r--r-- | Documentation/hwmon/isl68137 | 72 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/Kconfig | 9 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/Makefile | 1 | ||||
-rw-r--r-- | drivers/hwmon/pmbus/isl68137.c | 169 |
4 files changed, 251 insertions, 0 deletions
diff --git a/Documentation/hwmon/isl68137 b/Documentation/hwmon/isl68137 new file mode 100644 index 000000000000..92e5c5fc5b77 --- /dev/null +++ b/Documentation/hwmon/isl68137 | |||
@@ -0,0 +1,72 @@ | |||
1 | Kernel driver isl68137 | ||
2 | ====================== | ||
3 | |||
4 | Supported chips: | ||
5 | * Intersil ISL68137 | ||
6 | Prefix: 'isl68137' | ||
7 | Addresses scanned: - | ||
8 | Datasheet: Publicly available at the Intersil website | ||
9 | https://www.intersil.com/content/dam/Intersil/documents/isl6/isl68137.pdf | ||
10 | |||
11 | Authors: | ||
12 | Maxim Sloyko <maxims@google.com> | ||
13 | Robert Lippert <rlippert@google.com> | ||
14 | Patrick Venture <venture@google.com> | ||
15 | |||
16 | Description | ||
17 | ----------- | ||
18 | |||
19 | Intersil ISL68137 is a digital output 7-phase configurable PWM | ||
20 | controller with an AVSBus interface. | ||
21 | |||
22 | Usage Notes | ||
23 | ----------- | ||
24 | |||
25 | This driver does not probe for PMBus devices. You will have to instantiate | ||
26 | devices explicitly. | ||
27 | |||
28 | The ISL68137 AVS operation mode must be enabled/disabled at runtime. | ||
29 | |||
30 | Beyond the normal sysfs pmbus attributes, the driver exposes a control attribute. | ||
31 | |||
32 | Additional Sysfs attributes | ||
33 | --------------------------- | ||
34 | |||
35 | avs(0|1)_enable Controls the AVS state of each rail. | ||
36 | |||
37 | curr1_label "iin" | ||
38 | curr1_input Measured input current | ||
39 | curr1_crit Critical maximum current | ||
40 | curr1_crit_alarm Current critical high alarm | ||
41 | |||
42 | curr[2-3]_label "iout[1-2]" | ||
43 | curr[2-3]_input Measured output current | ||
44 | curr[2-3]_crit Critical maximum current | ||
45 | curr[2-3]_crit_alarm Current critical high alarm | ||
46 | |||
47 | in1_label "vin" | ||
48 | in1_input Measured input voltage | ||
49 | in1_lcrit Critical minimum input voltage | ||
50 | in1_lcrit_alarm Input voltage critical low alarm | ||
51 | in1_crit Critical maximum input voltage | ||
52 | in1_crit_alarm Input voltage critical high alarm | ||
53 | |||
54 | in[2-3]_label "vout[1-2]" | ||
55 | in[2-3]_input Measured output voltage | ||
56 | in[2-3]_lcrit Critical minimum output voltage | ||
57 | in[2-3]_lcrit_alarm Output voltage critical low alarm | ||
58 | in[2-3]_crit Critical maximum output voltage | ||
59 | in[2-3]_crit_alarm Output voltage critical high alarm | ||
60 | |||
61 | power1_label "pin" | ||
62 | power1_input Measured input power | ||
63 | power1_alarm Input power high alarm | ||
64 | |||
65 | power[2-3]_label "pout[1-2]" | ||
66 | power[2-3]_input Measured output power | ||
67 | |||
68 | temp[1-3]_input Measured temperature | ||
69 | temp[1-3]_crit Critical high temperature | ||
70 | temp[1-3]_crit_alarm Chip temperature critical high alarm | ||
71 | temp[1-3]_max Maximum temperature | ||
72 | temp[1-3]_max_alarm Chip temperature high alarm | ||
diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig index de87abab990e..7edab7e30eaf 100644 --- a/drivers/hwmon/pmbus/Kconfig +++ b/drivers/hwmon/pmbus/Kconfig | |||
@@ -63,6 +63,15 @@ config SENSORS_IR38064 | |||
63 | This driver can also be built as a module. If so, the module will | 63 | This driver can also be built as a module. If so, the module will |
64 | be called ir38064. | 64 | be called ir38064. |
65 | 65 | ||
66 | config SENSORS_ISL68137 | ||
67 | tristate "Intersil ISL68137" | ||
68 | help | ||
69 | If you say yes here you get hardware monitoring support for Intersil | ||
70 | ISL68137. | ||
71 | |||
72 | This driver can also be built as a module. If so, the module will | ||
73 | be called isl68137. | ||
74 | |||
66 | config SENSORS_LM25066 | 75 | config SENSORS_LM25066 |
67 | tristate "National Semiconductor LM25066 and compatibles" | 76 | tristate "National Semiconductor LM25066 and compatibles" |
68 | help | 77 | help |
diff --git a/drivers/hwmon/pmbus/Makefile b/drivers/hwmon/pmbus/Makefile index 7d1fa6b3c8c9..2219b9300316 100644 --- a/drivers/hwmon/pmbus/Makefile +++ b/drivers/hwmon/pmbus/Makefile | |||
@@ -9,6 +9,7 @@ obj-$(CONFIG_SENSORS_ADM1275) += adm1275.o | |||
9 | obj-$(CONFIG_SENSORS_IBM_CFFPS) += ibm-cffps.o | 9 | obj-$(CONFIG_SENSORS_IBM_CFFPS) += ibm-cffps.o |
10 | obj-$(CONFIG_SENSORS_IR35221) += ir35221.o | 10 | obj-$(CONFIG_SENSORS_IR35221) += ir35221.o |
11 | obj-$(CONFIG_SENSORS_IR38064) += ir38064.o | 11 | obj-$(CONFIG_SENSORS_IR38064) += ir38064.o |
12 | obj-$(CONFIG_SENSORS_ISL68137) += isl68137.o | ||
12 | obj-$(CONFIG_SENSORS_LM25066) += lm25066.o | 13 | obj-$(CONFIG_SENSORS_LM25066) += lm25066.o |
13 | obj-$(CONFIG_SENSORS_LTC2978) += ltc2978.o | 14 | obj-$(CONFIG_SENSORS_LTC2978) += ltc2978.o |
14 | obj-$(CONFIG_SENSORS_LTC3815) += ltc3815.o | 15 | obj-$(CONFIG_SENSORS_LTC3815) += ltc3815.o |
diff --git a/drivers/hwmon/pmbus/isl68137.c b/drivers/hwmon/pmbus/isl68137.c new file mode 100644 index 000000000000..515596c92fe1 --- /dev/null +++ b/drivers/hwmon/pmbus/isl68137.c | |||
@@ -0,0 +1,169 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0+ | ||
2 | /* | ||
3 | * Hardware monitoring driver for Intersil ISL68137 | ||
4 | * | ||
5 | * Copyright (c) 2017 Google Inc | ||
6 | * | ||
7 | */ | ||
8 | |||
9 | #include <linux/err.h> | ||
10 | #include <linux/hwmon-sysfs.h> | ||
11 | #include <linux/i2c.h> | ||
12 | #include <linux/init.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/string.h> | ||
16 | #include <linux/sysfs.h> | ||
17 | #include "pmbus.h" | ||
18 | |||
19 | #define ISL68137_VOUT_AVS 0x30 | ||
20 | |||
21 | static ssize_t isl68137_avs_enable_show_page(struct i2c_client *client, | ||
22 | int page, | ||
23 | char *buf) | ||
24 | { | ||
25 | int val = pmbus_read_byte_data(client, page, PMBUS_OPERATION); | ||
26 | |||
27 | return sprintf(buf, "%d\n", | ||
28 | (val & ISL68137_VOUT_AVS) == ISL68137_VOUT_AVS ? 1 : 0); | ||
29 | } | ||
30 | |||
31 | static ssize_t isl68137_avs_enable_store_page(struct i2c_client *client, | ||
32 | int page, | ||
33 | const char *buf, size_t count) | ||
34 | { | ||
35 | int rc, op_val; | ||
36 | bool result; | ||
37 | |||
38 | rc = kstrtobool(buf, &result); | ||
39 | if (rc) | ||
40 | return rc; | ||
41 | |||
42 | op_val = result ? ISL68137_VOUT_AVS : 0; | ||
43 | |||
44 | /* | ||
45 | * Writes to VOUT setpoint over AVSBus will persist after the VRM is | ||
46 | * switched to PMBus control. Switching back to AVSBus control | ||
47 | * restores this persisted setpoint rather than re-initializing to | ||
48 | * PMBus VOUT_COMMAND. Writing VOUT_COMMAND first over PMBus before | ||
49 | * enabling AVS control is the workaround. | ||
50 | */ | ||
51 | if (op_val == ISL68137_VOUT_AVS) { | ||
52 | rc = pmbus_read_word_data(client, page, PMBUS_VOUT_COMMAND); | ||
53 | if (rc < 0) | ||
54 | return rc; | ||
55 | |||
56 | rc = pmbus_write_word_data(client, page, PMBUS_VOUT_COMMAND, | ||
57 | rc); | ||
58 | if (rc < 0) | ||
59 | return rc; | ||
60 | } | ||
61 | |||
62 | rc = pmbus_update_byte_data(client, page, PMBUS_OPERATION, | ||
63 | ISL68137_VOUT_AVS, op_val); | ||
64 | |||
65 | return (rc < 0) ? rc : count; | ||
66 | } | ||
67 | |||
68 | static ssize_t isl68137_avs_enable_show(struct device *dev, | ||
69 | struct device_attribute *devattr, | ||
70 | char *buf) | ||
71 | { | ||
72 | struct i2c_client *client = to_i2c_client(dev->parent); | ||
73 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
74 | |||
75 | return isl68137_avs_enable_show_page(client, attr->index, buf); | ||
76 | } | ||
77 | |||
78 | static ssize_t isl68137_avs_enable_store(struct device *dev, | ||
79 | struct device_attribute *devattr, | ||
80 | const char *buf, size_t count) | ||
81 | { | ||
82 | struct i2c_client *client = to_i2c_client(dev->parent); | ||
83 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
84 | |||
85 | return isl68137_avs_enable_store_page(client, attr->index, buf, count); | ||
86 | } | ||
87 | |||
88 | static SENSOR_DEVICE_ATTR_RW(avs0_enable, isl68137_avs_enable, 0); | ||
89 | static SENSOR_DEVICE_ATTR_RW(avs1_enable, isl68137_avs_enable, 1); | ||
90 | |||
91 | static struct attribute *enable_attrs[] = { | ||
92 | &sensor_dev_attr_avs0_enable.dev_attr.attr, | ||
93 | &sensor_dev_attr_avs1_enable.dev_attr.attr, | ||
94 | NULL, | ||
95 | }; | ||
96 | |||
97 | static const struct attribute_group enable_group = { | ||
98 | .attrs = enable_attrs, | ||
99 | }; | ||
100 | |||
101 | static const struct attribute_group *attribute_groups[] = { | ||
102 | &enable_group, | ||
103 | NULL, | ||
104 | }; | ||
105 | |||
106 | static struct pmbus_driver_info isl68137_info = { | ||
107 | .pages = 2, | ||
108 | .format[PSC_VOLTAGE_IN] = direct, | ||
109 | .format[PSC_VOLTAGE_OUT] = direct, | ||
110 | .format[PSC_CURRENT_IN] = direct, | ||
111 | .format[PSC_CURRENT_OUT] = direct, | ||
112 | .format[PSC_POWER] = direct, | ||
113 | .format[PSC_TEMPERATURE] = direct, | ||
114 | .m[PSC_VOLTAGE_IN] = 1, | ||
115 | .b[PSC_VOLTAGE_IN] = 0, | ||
116 | .R[PSC_VOLTAGE_IN] = 3, | ||
117 | .m[PSC_VOLTAGE_OUT] = 1, | ||
118 | .b[PSC_VOLTAGE_OUT] = 0, | ||
119 | .R[PSC_VOLTAGE_OUT] = 3, | ||
120 | .m[PSC_CURRENT_IN] = 1, | ||
121 | .b[PSC_CURRENT_IN] = 0, | ||
122 | .R[PSC_CURRENT_IN] = 2, | ||
123 | .m[PSC_CURRENT_OUT] = 1, | ||
124 | .b[PSC_CURRENT_OUT] = 0, | ||
125 | .R[PSC_CURRENT_OUT] = 1, | ||
126 | .m[PSC_POWER] = 1, | ||
127 | .b[PSC_POWER] = 0, | ||
128 | .R[PSC_POWER] = 0, | ||
129 | .m[PSC_TEMPERATURE] = 1, | ||
130 | .b[PSC_TEMPERATURE] = 0, | ||
131 | .R[PSC_TEMPERATURE] = 0, | ||
132 | .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_PIN | ||
133 | | PMBUS_HAVE_STATUS_INPUT | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | ||
134 | | PMBUS_HAVE_TEMP3 | PMBUS_HAVE_STATUS_TEMP | ||
135 | | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | ||
136 | | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, | ||
137 | .func[1] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | ||
138 | | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT, | ||
139 | .groups = attribute_groups, | ||
140 | }; | ||
141 | |||
142 | static int isl68137_probe(struct i2c_client *client, | ||
143 | const struct i2c_device_id *id) | ||
144 | { | ||
145 | return pmbus_do_probe(client, id, &isl68137_info); | ||
146 | } | ||
147 | |||
148 | static const struct i2c_device_id isl68137_id[] = { | ||
149 | {"isl68137", 0}, | ||
150 | {} | ||
151 | }; | ||
152 | |||
153 | MODULE_DEVICE_TABLE(i2c, isl68137_id); | ||
154 | |||
155 | /* This is the driver that will be inserted */ | ||
156 | static struct i2c_driver isl68137_driver = { | ||
157 | .driver = { | ||
158 | .name = "isl68137", | ||
159 | }, | ||
160 | .probe = isl68137_probe, | ||
161 | .remove = pmbus_do_remove, | ||
162 | .id_table = isl68137_id, | ||
163 | }; | ||
164 | |||
165 | module_i2c_driver(isl68137_driver); | ||
166 | |||
167 | MODULE_AUTHOR("Maxim Sloyko <maxims@google.com>"); | ||
168 | MODULE_DESCRIPTION("PMBus driver for Intersil ISL68137"); | ||
169 | MODULE_LICENSE("GPL"); | ||