]> Git Repo - J-linux.git/blob - drivers/hwmon/isl28022.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / hwmon / isl28022.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * isl28022.c - driver for Renesas ISL28022 power monitor chip monitoring
4  *
5  * Copyright (c) 2023 Carsten Spieß <[email protected]>
6  */
7
8 #include <linux/debugfs.h>
9 #include <linux/err.h>
10 #include <linux/hwmon.h>
11 #include <linux/i2c.h>
12 #include <linux/module.h>
13 #include <linux/regmap.h>
14
15 /* ISL28022 registers */
16 #define ISL28022_REG_CONFIG     0x00
17 #define ISL28022_REG_SHUNT      0x01
18 #define ISL28022_REG_BUS        0x02
19 #define ISL28022_REG_POWER      0x03
20 #define ISL28022_REG_CURRENT    0x04
21 #define ISL28022_REG_CALIB      0x05
22 #define ISL28022_REG_SHUNT_THR  0x06
23 #define ISL28022_REG_BUS_THR    0x07
24 #define ISL28022_REG_INT        0x08
25 #define ISL28022_REG_AUX        0x09
26 #define ISL28022_REG_MAX        ISL28022_REG_AUX
27
28 /* ISL28022 config flags */
29 /* mode flags */
30 #define ISL28022_MODE_SHIFT     0
31 #define ISL28022_MODE_MASK      0x0007
32
33 #define ISL28022_MODE_PWR_DOWN  0x0
34 #define ISL28022_MODE_TRG_S     0x1
35 #define ISL28022_MODE_TRG_B     0x2
36 #define ISL28022_MODE_TRG_SB    0x3
37 #define ISL28022_MODE_ADC_OFF   0x4
38 #define ISL28022_MODE_CONT_S    0x5
39 #define ISL28022_MODE_CONT_B    0x6
40 #define ISL28022_MODE_CONT_SB   0x7
41
42 /* shunt ADC settings */
43 #define ISL28022_SADC_SHIFT     3
44 #define ISL28022_SADC_MASK      0x0078
45
46 #define ISL28022_BADC_SHIFT     7
47 #define ISL28022_BADC_MASK      0x0780
48
49 #define ISL28022_ADC_12         0x0     /* 12 bit ADC */
50 #define ISL28022_ADC_13         0x1     /* 13 bit ADC */
51 #define ISL28022_ADC_14         0x2     /* 14 bit ADC */
52 #define ISL28022_ADC_15         0x3     /* 15 bit ADC */
53 #define ISL28022_ADC_15_1       0x8     /* 15 bit ADC, 1 sample */
54 #define ISL28022_ADC_15_2       0x9     /* 15 bit ADC, 2 samples */
55 #define ISL28022_ADC_15_4       0xA     /* 15 bit ADC, 4 samples */
56 #define ISL28022_ADC_15_8       0xB     /* 15 bit ADC, 8 samples */
57 #define ISL28022_ADC_15_16      0xC     /* 15 bit ADC, 16 samples */
58 #define ISL28022_ADC_15_32      0xD     /* 15 bit ADC, 32 samples */
59 #define ISL28022_ADC_15_64      0xE     /* 15 bit ADC, 64 samples */
60 #define ISL28022_ADC_15_128     0xF     /* 15 bit ADC, 128 samples */
61
62 /* shunt voltage range */
63 #define ISL28022_PG_SHIFT       11
64 #define ISL28022_PG_MASK        0x1800
65
66 #define ISL28022_PG_40          0x0     /* +/-40 mV */
67 #define ISL28022_PG_80          0x1     /* +/-80 mV */
68 #define ISL28022_PG_160         0x2     /* +/-160 mV */
69 #define ISL28022_PG_320         0x3     /* +/-3200 mV */
70
71 /* bus voltage range */
72 #define ISL28022_BRNG_SHIFT     13
73 #define ISL28022_BRNG_MASK      0x6000
74
75 #define ISL28022_BRNG_16        0x0     /* 16 V */
76 #define ISL28022_BRNG_32        0x1     /* 32 V */
77 #define ISL28022_BRNG_60        0x3     /* 60 V */
78
79 /* reset */
80 #define ISL28022_RESET          0x8000
81
82 struct isl28022_data {
83         struct regmap           *regmap;
84         u32                     shunt;
85         u32                     gain;
86         u32                     average;
87 };
88
89 static int isl28022_read_in(struct device *dev, u32 attr, int channel, long *val)
90 {
91         struct isl28022_data *data = dev_get_drvdata(dev);
92         unsigned int regval;
93         int err;
94         u16 sign_bit;
95
96         switch (channel) {
97         case 0:
98                 switch (attr) {
99                 case hwmon_in_input:
100                         err = regmap_read(data->regmap,
101                                           ISL28022_REG_BUS, &regval);
102                         if (err < 0)
103                                 return err;
104                         /* driver supports only 60V mode (BRNG 11) */
105                         *val = (long)(((u16)regval) & 0xFFFC);
106                         break;
107                 default:
108                         return -EOPNOTSUPP;
109                 }
110                 break;
111         case 1:
112                 switch (attr) {
113                 case hwmon_in_input:
114                         err = regmap_read(data->regmap,
115                                           ISL28022_REG_SHUNT, &regval);
116                         if (err < 0)
117                                 return err;
118                         switch (data->gain) {
119                         case 8:
120                                 sign_bit = (regval >> 15) & 0x01;
121                                 *val = (long)((((u16)regval) & 0x7FFF) -
122                                         (sign_bit * 32768)) / 100;
123                                 break;
124                         case 4:
125                                 sign_bit = (regval >> 14) & 0x01;
126                                 *val = (long)((((u16)regval) & 0x3FFF) -
127                                         (sign_bit * 16384)) / 100;
128                                 break;
129                         case 2:
130                                 sign_bit = (regval >> 13) & 0x01;
131                                 *val = (long)((((u16)regval) & 0x1FFF) -
132                                         (sign_bit * 8192)) / 100;
133                                 break;
134                         case 1:
135                                 sign_bit = (regval >> 12) & 0x01;
136                                 *val = (long)((((u16)regval) & 0x0FFF) -
137                                         (sign_bit * 4096)) / 100;
138                                 break;
139                         }
140                         break;
141                 default:
142                         return -EOPNOTSUPP;
143                 }
144                 break;
145         default:
146                 return -EOPNOTSUPP;
147         }
148
149         return 0;
150 }
151
152 static int isl28022_read_current(struct device *dev, u32 attr, long *val)
153 {
154         struct isl28022_data *data = dev_get_drvdata(dev);
155         unsigned int regval;
156         int err;
157
158         switch (attr) {
159         case hwmon_curr_input:
160                 err = regmap_read(data->regmap,
161                                   ISL28022_REG_CURRENT, &regval);
162                 if (err < 0)
163                         return err;
164                 *val = ((long)regval * 1250L * (long)data->gain) /
165                         (long)data->shunt;
166                 break;
167         default:
168                 return -EOPNOTSUPP;
169         }
170
171         return 0;
172 }
173
174 static int isl28022_read_power(struct device *dev, u32 attr, long *val)
175 {
176         struct isl28022_data *data = dev_get_drvdata(dev);
177         unsigned int regval;
178         int err;
179
180         switch (attr) {
181         case hwmon_power_input:
182                 err = regmap_read(data->regmap,
183                                   ISL28022_REG_POWER, &regval);
184                 if (err < 0)
185                         return err;
186                 *val = ((51200000L * ((long)data->gain)) /
187                         (long)data->shunt) * (long)regval;
188                 break;
189         default:
190                 return -EOPNOTSUPP;
191         }
192
193         return 0;
194 }
195
196 static int isl28022_read(struct device *dev, enum hwmon_sensor_types type,
197                          u32 attr, int channel, long *val)
198 {
199         switch (type) {
200         case hwmon_in:
201                 return isl28022_read_in(dev, attr, channel, val);
202         case hwmon_curr:
203                 return isl28022_read_current(dev, attr, val);
204         case hwmon_power:
205                 return isl28022_read_power(dev, attr, val);
206         default:
207                 return -EOPNOTSUPP;
208         }
209         return 0;
210 }
211
212 static umode_t isl28022_is_visible(const void *data, enum hwmon_sensor_types type,
213                                    u32 attr, int channel)
214 {
215         switch (type) {
216         case hwmon_in:
217                 switch (attr) {
218                 case hwmon_in_input:
219                         return 0444;
220                 default:
221                         break;
222                 }
223                 break;
224         case hwmon_curr:
225                 switch (attr) {
226                 case hwmon_curr_input:
227                         return 0444;
228                 default:
229                         break;
230                 }
231                 break;
232         case hwmon_power:
233                 switch (attr) {
234                 case hwmon_power_input:
235                         return 0444;
236                 default:
237                         break;
238                 }
239                 break;
240         default:
241                 break;
242         }
243         return 0;
244 }
245
246 static const struct hwmon_channel_info *isl28022_info[] = {
247         HWMON_CHANNEL_INFO(in,
248                            HWMON_I_INPUT,       /* channel 0: bus voltage (mV) */
249                            HWMON_I_INPUT),      /* channel 1: shunt voltage (mV) */
250         HWMON_CHANNEL_INFO(curr,
251                            HWMON_C_INPUT),      /* channel 1: current (mA) */
252         HWMON_CHANNEL_INFO(power,
253                            HWMON_P_INPUT),      /* channel 1: power (µW) */
254         NULL
255 };
256
257 static const struct hwmon_ops isl28022_hwmon_ops = {
258         .is_visible = isl28022_is_visible,
259         .read = isl28022_read,
260 };
261
262 static const struct hwmon_chip_info isl28022_chip_info = {
263         .ops = &isl28022_hwmon_ops,
264         .info = isl28022_info,
265 };
266
267 static bool isl28022_is_writeable_reg(struct device *dev, unsigned int reg)
268 {
269         switch (reg) {
270         case ISL28022_REG_CONFIG:
271         case ISL28022_REG_CALIB:
272         case ISL28022_REG_SHUNT_THR:
273         case ISL28022_REG_BUS_THR:
274         case ISL28022_REG_INT:
275         case ISL28022_REG_AUX:
276                 return true;
277         }
278
279         return false;
280 }
281
282 static bool isl28022_is_volatile_reg(struct device *dev, unsigned int reg)
283 {
284         switch (reg) {
285         case ISL28022_REG_CONFIG:
286         case ISL28022_REG_SHUNT:
287         case ISL28022_REG_BUS:
288         case ISL28022_REG_POWER:
289         case ISL28022_REG_CURRENT:
290         case ISL28022_REG_INT:
291         case ISL28022_REG_AUX:
292                 return true;
293         }
294         return true;
295 }
296
297 static const struct regmap_config isl28022_regmap_config = {
298         .reg_bits = 8,
299         .val_bits = 16,
300         .max_register = ISL28022_REG_MAX,
301         .writeable_reg = isl28022_is_writeable_reg,
302         .volatile_reg = isl28022_is_volatile_reg,
303         .val_format_endian = REGMAP_ENDIAN_BIG,
304         .cache_type = REGCACHE_RBTREE,
305         .use_single_read = true,
306         .use_single_write = true,
307 };
308
309 static int shunt_voltage_show(struct seq_file *seqf, void *unused)
310 {
311         struct isl28022_data *data = seqf->private;
312         unsigned int regval;
313         int err;
314
315         err = regmap_read(data->regmap,
316                           ISL28022_REG_SHUNT, &regval);
317         if (err)
318                 return err;
319
320         /* print shunt voltage in micro volt  */
321         seq_printf(seqf, "%d\n", regval * 10);
322
323         return 0;
324 }
325 DEFINE_SHOW_ATTRIBUTE(shunt_voltage);
326
327 static struct dentry *isl28022_debugfs_root;
328
329 static void isl28022_debugfs_remove(void *res)
330 {
331         debugfs_remove_recursive(res);
332 }
333
334 static void isl28022_debugfs_init(struct i2c_client *client, struct isl28022_data *data)
335 {
336         char name[16];
337         struct dentry *debugfs;
338
339         scnprintf(name, sizeof(name), "%d-%04hx", client->adapter->nr, client->addr);
340
341         debugfs = debugfs_create_dir(name, isl28022_debugfs_root);
342         debugfs_create_file("shunt_voltage", 0444, debugfs, data, &shunt_voltage_fops);
343
344         devm_add_action_or_reset(&client->dev, isl28022_debugfs_remove, debugfs);
345 }
346
347 /*
348  * read property values and make consistency checks.
349  *
350  * following values for shunt range and resistor are allowed:
351  *   40 mV -> gain 1, shunt min.  800 micro ohms
352  *   80 mV -> gain 2, shunt min. 1600 micro ohms
353  *  160 mV -> gain 4, shunt min. 3200 micro ohms
354  *  320 mV -> gain 8, shunt min. 6400 micro ohms
355  */
356 static int isl28022_read_properties(struct device *dev, struct isl28022_data *data)
357 {
358         u32 val;
359         int err;
360
361         err = device_property_read_u32(dev, "shunt-resistor-micro-ohms", &val);
362         if (err == -EINVAL)
363                 val = 10000;
364         else if (err < 0)
365                 return err;
366         data->shunt = val;
367
368         err = device_property_read_u32(dev, "renesas,shunt-range-microvolt", &val);
369         if (err == -EINVAL)
370                 val = 320000;
371         else if (err < 0)
372                 return err;
373
374         switch (val) {
375         case 40000:
376                 data->gain = 1;
377                 if (data->shunt < 800)
378                         goto shunt_invalid;
379                 break;
380         case 80000:
381                 data->gain = 2;
382                 if (data->shunt < 1600)
383                         goto shunt_invalid;
384                 break;
385         case 160000:
386                 data->gain = 4;
387                 if (data->shunt < 3200)
388                         goto shunt_invalid;
389                 break;
390         case 320000:
391                 data->gain = 8;
392                 if (data->shunt < 6400)
393                         goto shunt_invalid;
394                 break;
395         default:
396                 return dev_err_probe(dev, -EINVAL,
397                                      "renesas,shunt-range-microvolt invalid value %d\n",
398                                      val);
399         }
400
401         err = device_property_read_u32(dev, "renesas,average-samples", &val);
402         if (err == -EINVAL)
403                 val = 1;
404         else if (err < 0)
405                 return err;
406         if (val > 128 || hweight32(val) != 1)
407                 return dev_err_probe(dev, -EINVAL,
408                                      "renesas,average-samples invalid value %d\n",
409                                      val);
410
411         data->average = val;
412
413         return 0;
414
415 shunt_invalid:
416         return dev_err_probe(dev, -EINVAL,
417                              "renesas,shunt-resistor-microvolt invalid value %d\n",
418                              data->shunt);
419 }
420
421 /*
422  * write configuration and calibration registers
423  *
424  * The driver supports only shunt and bus continuous ADC mode at 15bit resolution
425  * with averaging from 1 to 128 samples (pow of 2) on both channels.
426  * Shunt voltage gain 1,2,4 or 8 is allowed.
427  * The bus voltage range is 60V fixed.
428  */
429 static int isl28022_config(struct isl28022_data *data)
430 {
431         int err;
432         u16 config;
433         u16 calib;
434
435         config = (ISL28022_MODE_CONT_SB << ISL28022_MODE_SHIFT) |
436                         (ISL28022_BRNG_60 << ISL28022_BRNG_SHIFT) |
437                         (__ffs(data->gain) << ISL28022_PG_SHIFT) |
438                         ((ISL28022_ADC_15_1 + __ffs(data->average)) << ISL28022_SADC_SHIFT) |
439                         ((ISL28022_ADC_15_1 + __ffs(data->average)) << ISL28022_BADC_SHIFT);
440
441         calib = data->shunt ? 0x8000 / data->gain : 0;
442
443         err = regmap_write(data->regmap, ISL28022_REG_CONFIG, config);
444         if (err < 0)
445                 return err;
446
447         return regmap_write(data->regmap, ISL28022_REG_CALIB, calib);
448 }
449
450 static int isl28022_probe(struct i2c_client *client)
451 {
452         struct device *dev = &client->dev;
453         struct device *hwmon_dev;
454         struct isl28022_data *data;
455         int err;
456
457         if (!i2c_check_functionality(client->adapter,
458                                      I2C_FUNC_SMBUS_BYTE_DATA |
459                                      I2C_FUNC_SMBUS_WORD_DATA))
460                 return -ENODEV;
461
462         data = devm_kzalloc(dev, sizeof(struct isl28022_data), GFP_KERNEL);
463         if (!data)
464                 return -ENOMEM;
465
466         err = isl28022_read_properties(dev, data);
467         if (err)
468                 return err;
469
470         data->regmap = devm_regmap_init_i2c(client, &isl28022_regmap_config);
471         if (IS_ERR(data->regmap))
472                 return PTR_ERR(data->regmap);
473
474         err = isl28022_config(data);
475         if (err)
476                 return err;
477
478         isl28022_debugfs_init(client, data);
479
480         hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name,
481                                                          data, &isl28022_chip_info, NULL);
482         if (IS_ERR(hwmon_dev))
483                 return PTR_ERR(hwmon_dev);
484
485         return 0;
486 }
487
488 static const struct i2c_device_id isl28022_ids[] = {
489         { "isl28022", 0},
490         { /* LIST END */ }
491 };
492 MODULE_DEVICE_TABLE(i2c, isl28022_ids);
493
494 static const struct of_device_id __maybe_unused isl28022_of_match[] = {
495         { .compatible = "renesas,isl28022"},
496         { /* LIST END */ }
497 };
498 MODULE_DEVICE_TABLE(of, isl28022_of_match);
499
500 static struct i2c_driver isl28022_driver = {
501         .class          = I2C_CLASS_HWMON,
502         .driver = {
503                 .name   = "isl28022",
504         },
505         .probe  = isl28022_probe,
506         .id_table       = isl28022_ids,
507 };
508
509 static int __init
510 isl28022_init(void)
511 {
512         int err;
513
514         isl28022_debugfs_root = debugfs_create_dir("isl28022", NULL);
515         err = i2c_add_driver(&isl28022_driver);
516         if (!err)
517                 return 0;
518
519         debugfs_remove_recursive(isl28022_debugfs_root);
520         return err;
521 }
522
523 static void __exit
524 isl28022_exit(void)
525 {
526         i2c_del_driver(&isl28022_driver);
527         debugfs_remove_recursive(isl28022_debugfs_root);
528 }
529
530 module_init(isl28022_init);
531 module_exit(isl28022_exit);
532
533 MODULE_AUTHOR("Carsten Spieß <[email protected]>");
534 MODULE_DESCRIPTION("ISL28022 driver");
535 MODULE_LICENSE("GPL");
This page took 0.082453 seconds and 4 git commands to generate.