treewide: Replace GPLv2 boilerplate/reference with SPDX - rule 157
[sfrench/cifs-2.6.git] / drivers / hwmon / pmbus / ltc3815.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Hardware monitoring driver for LTC3815
4  *
5  * Copyright (c) 2015 Linear Technology
6  * Copyright (c) 2015 Guenter Roeck
7  */
8
9 #include <linux/err.h>
10 #include <linux/i2c.h>
11 #include <linux/init.h>
12 #include <linux/jiffies.h>
13 #include <linux/kernel.h>
14 #include <linux/module.h>
15 #include "pmbus.h"
16
17 #define LTC3815_MFR_IOUT_PEAK   0xd7
18 #define LTC3815_MFR_VOUT_PEAK   0xdd
19 #define LTC3815_MFR_VIN_PEAK    0xde
20 #define LTC3815_MFR_TEMP_PEAK   0xdf
21 #define LTC3815_MFR_IIN_PEAK    0xe1
22 #define LTC3815_MFR_SPECIAL_ID  0xe7
23
24 #define LTC3815_ID              0x8000
25 #define LTC3815_ID_MASK         0xff00
26
27 static int ltc3815_read_byte_data(struct i2c_client *client, int page, int reg)
28 {
29         int ret;
30
31         switch (reg) {
32         case PMBUS_VOUT_MODE:
33                 /*
34                  * The chip returns 0x3e, suggesting VID mode with manufacturer
35                  * specific VID codes. Since the output voltage is reported
36                  * with a LSB of 0.5mV, override and report direct mode with
37                  * appropriate coefficients.
38                  */
39                 ret = 0x40;
40                 break;
41         default:
42                 ret = -ENODATA;
43                 break;
44         }
45         return ret;
46 }
47
48 static int ltc3815_write_byte(struct i2c_client *client, int page, u8 reg)
49 {
50         int ret;
51
52         switch (reg) {
53         case PMBUS_CLEAR_FAULTS:
54                 /*
55                  * LTC3815 does not support the CLEAR_FAULTS command.
56                  * Emulate it by clearing the status register.
57                  */
58                 ret = pmbus_read_word_data(client, 0, PMBUS_STATUS_WORD);
59                 if (ret > 0) {
60                         pmbus_write_word_data(client, 0, PMBUS_STATUS_WORD,
61                                               ret);
62                         ret = 0;
63                 }
64                 break;
65         default:
66                 ret = -ENODATA;
67                 break;
68         }
69         return ret;
70 }
71
72 static int ltc3815_read_word_data(struct i2c_client *client, int page, int reg)
73 {
74         int ret;
75
76         switch (reg) {
77         case PMBUS_VIRT_READ_VIN_MAX:
78                 ret = pmbus_read_word_data(client, page, LTC3815_MFR_VIN_PEAK);
79                 break;
80         case PMBUS_VIRT_READ_VOUT_MAX:
81                 ret = pmbus_read_word_data(client, page, LTC3815_MFR_VOUT_PEAK);
82                 break;
83         case PMBUS_VIRT_READ_TEMP_MAX:
84                 ret = pmbus_read_word_data(client, page, LTC3815_MFR_TEMP_PEAK);
85                 break;
86         case PMBUS_VIRT_READ_IOUT_MAX:
87                 ret = pmbus_read_word_data(client, page, LTC3815_MFR_IOUT_PEAK);
88                 break;
89         case PMBUS_VIRT_READ_IIN_MAX:
90                 ret = pmbus_read_word_data(client, page, LTC3815_MFR_IIN_PEAK);
91                 break;
92         case PMBUS_VIRT_RESET_VOUT_HISTORY:
93         case PMBUS_VIRT_RESET_VIN_HISTORY:
94         case PMBUS_VIRT_RESET_TEMP_HISTORY:
95         case PMBUS_VIRT_RESET_IOUT_HISTORY:
96         case PMBUS_VIRT_RESET_IIN_HISTORY:
97                 ret = 0;
98                 break;
99         default:
100                 ret = -ENODATA;
101                 break;
102         }
103         return ret;
104 }
105
106 static int ltc3815_write_word_data(struct i2c_client *client, int page,
107                                    int reg, u16 word)
108 {
109         int ret;
110
111         switch (reg) {
112         case PMBUS_VIRT_RESET_IIN_HISTORY:
113                 ret = pmbus_write_word_data(client, page,
114                                             LTC3815_MFR_IIN_PEAK, 0);
115                 break;
116         case PMBUS_VIRT_RESET_IOUT_HISTORY:
117                 ret = pmbus_write_word_data(client, page,
118                                             LTC3815_MFR_IOUT_PEAK, 0);
119                 break;
120         case PMBUS_VIRT_RESET_VOUT_HISTORY:
121                 ret = pmbus_write_word_data(client, page,
122                                             LTC3815_MFR_VOUT_PEAK, 0);
123                 break;
124         case PMBUS_VIRT_RESET_VIN_HISTORY:
125                 ret = pmbus_write_word_data(client, page,
126                                             LTC3815_MFR_VIN_PEAK, 0);
127                 break;
128         case PMBUS_VIRT_RESET_TEMP_HISTORY:
129                 ret = pmbus_write_word_data(client, page,
130                                             LTC3815_MFR_TEMP_PEAK, 0);
131                 break;
132         default:
133                 ret = -ENODATA;
134                 break;
135         }
136         return ret;
137 }
138
139 static const struct i2c_device_id ltc3815_id[] = {
140         {"ltc3815", 0},
141         { }
142 };
143 MODULE_DEVICE_TABLE(i2c, ltc3815_id);
144
145 static struct pmbus_driver_info ltc3815_info = {
146         .pages = 1,
147         .format[PSC_VOLTAGE_IN] = direct,
148         .format[PSC_VOLTAGE_OUT] = direct,
149         .format[PSC_CURRENT_IN] = direct,
150         .format[PSC_CURRENT_OUT] = direct,
151         .format[PSC_TEMPERATURE] = direct,
152         .m[PSC_VOLTAGE_IN] = 250,
153         .b[PSC_VOLTAGE_IN] = 0,
154         .R[PSC_VOLTAGE_IN] = 0,
155         .m[PSC_VOLTAGE_OUT] = 2,
156         .b[PSC_VOLTAGE_OUT] = 0,
157         .R[PSC_VOLTAGE_OUT] = 3,
158         .m[PSC_CURRENT_IN] = 1,
159         .b[PSC_CURRENT_IN] = 0,
160         .R[PSC_CURRENT_IN] = 2,
161         .m[PSC_CURRENT_OUT] = 1,
162         .b[PSC_CURRENT_OUT] = 0,
163         .R[PSC_CURRENT_OUT] = 2,
164         .m[PSC_TEMPERATURE] = 1,
165         .b[PSC_TEMPERATURE] = 0,
166         .R[PSC_TEMPERATURE] = 0,
167         .func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_VOUT |
168                 PMBUS_HAVE_IOUT | PMBUS_HAVE_TEMP,
169         .read_byte_data = ltc3815_read_byte_data,
170         .read_word_data = ltc3815_read_word_data,
171         .write_byte = ltc3815_write_byte,
172         .write_word_data = ltc3815_write_word_data,
173 };
174
175 static int ltc3815_probe(struct i2c_client *client,
176                          const struct i2c_device_id *id)
177 {
178         int chip_id;
179
180         if (!i2c_check_functionality(client->adapter,
181                                      I2C_FUNC_SMBUS_READ_WORD_DATA))
182                 return -ENODEV;
183
184         chip_id = i2c_smbus_read_word_data(client, LTC3815_MFR_SPECIAL_ID);
185         if (chip_id < 0)
186                 return chip_id;
187         if ((chip_id & LTC3815_ID_MASK) != LTC3815_ID)
188                 return -ENODEV;
189
190         return pmbus_do_probe(client, id, &ltc3815_info);
191 }
192
193 static struct i2c_driver ltc3815_driver = {
194         .driver = {
195                    .name = "ltc3815",
196                    },
197         .probe = ltc3815_probe,
198         .remove = pmbus_do_remove,
199         .id_table = ltc3815_id,
200 };
201
202 module_i2c_driver(ltc3815_driver);
203
204 MODULE_AUTHOR("Guenter Roeck");
205 MODULE_DESCRIPTION("PMBus driver for LTC3815");
206 MODULE_LICENSE("GPL");