1 // SPDX-License-Identifier: GPL-2.0+
3 * Hardware monitoring driver for Intersil ISL68137
5 * Copyright (c) 2017 Google Inc
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>
19 #define ISL68137_VOUT_AVS 0x30
21 static ssize_t
isl68137_avs_enable_show_page(struct i2c_client
*client
,
25 int val
= pmbus_read_byte_data(client
, page
, PMBUS_OPERATION
);
27 return sprintf(buf
, "%d\n",
28 (val
& ISL68137_VOUT_AVS
) == ISL68137_VOUT_AVS
? 1 : 0);
31 static ssize_t
isl68137_avs_enable_store_page(struct i2c_client
*client
,
33 const char *buf
, size_t count
)
38 rc
= kstrtobool(buf
, &result
);
42 op_val
= result
? ISL68137_VOUT_AVS
: 0;
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.
51 if (op_val
== ISL68137_VOUT_AVS
) {
52 rc
= pmbus_read_word_data(client
, page
, PMBUS_VOUT_COMMAND
);
56 rc
= pmbus_write_word_data(client
, page
, PMBUS_VOUT_COMMAND
,
62 rc
= pmbus_update_byte_data(client
, page
, PMBUS_OPERATION
,
63 ISL68137_VOUT_AVS
, op_val
);
65 return (rc
< 0) ? rc
: count
;
68 static ssize_t
isl68137_avs_enable_show(struct device
*dev
,
69 struct device_attribute
*devattr
,
72 struct i2c_client
*client
= to_i2c_client(dev
->parent
);
73 struct sensor_device_attribute
*attr
= to_sensor_dev_attr(devattr
);
75 return isl68137_avs_enable_show_page(client
, attr
->index
, buf
);
78 static ssize_t
isl68137_avs_enable_store(struct device
*dev
,
79 struct device_attribute
*devattr
,
80 const char *buf
, size_t count
)
82 struct i2c_client
*client
= to_i2c_client(dev
->parent
);
83 struct sensor_device_attribute
*attr
= to_sensor_dev_attr(devattr
);
85 return isl68137_avs_enable_store_page(client
, attr
->index
, buf
, count
);
88 static SENSOR_DEVICE_ATTR_RW(avs0_enable
, isl68137_avs_enable
, 0);
89 static SENSOR_DEVICE_ATTR_RW(avs1_enable
, isl68137_avs_enable
, 1);
91 static struct attribute
*enable_attrs
[] = {
92 &sensor_dev_attr_avs0_enable
.dev_attr
.attr
,
93 &sensor_dev_attr_avs1_enable
.dev_attr
.attr
,
97 static const struct attribute_group enable_group
= {
98 .attrs
= enable_attrs
,
101 static const struct attribute_group
*attribute_groups
[] = {
106 static struct pmbus_driver_info isl68137_info
= {
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,
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
,
142 static int isl68137_probe(struct i2c_client
*client
,
143 const struct i2c_device_id
*id
)
145 return pmbus_do_probe(client
, id
, &isl68137_info
);
148 static const struct i2c_device_id isl68137_id
[] = {
153 MODULE_DEVICE_TABLE(i2c
, isl68137_id
);
155 /* This is the driver that will be inserted */
156 static struct i2c_driver isl68137_driver
= {
160 .probe
= isl68137_probe
,
161 .remove
= pmbus_do_remove
,
162 .id_table
= isl68137_id
,
165 module_i2c_driver(isl68137_driver
);
167 MODULE_AUTHOR("Maxim Sloyko <maxims@google.com>");
168 MODULE_DESCRIPTION("PMBus driver for Intersil ISL68137");
169 MODULE_LICENSE("GPL");