13
13
#include <linux/init.h>
14
14
#include <linux/kernel.h>
15
15
#include <linux/module.h>
16
+ #include <linux/of.h>
16
17
#include <linux/string.h>
17
18
#include <linux/sysfs.h>
18
19
19
20
#include "pmbus.h"
20
21
21
22
#define ISL68137_VOUT_AVS 0x30
22
23
#define RAA_DMPVR2_READ_VMON 0xc8
24
+ #define MAX_CHANNELS 4
23
25
24
26
enum chips {
25
27
isl68137 ,
@@ -72,6 +74,17 @@ enum variants {
72
74
raa_dmpvr2_hv ,
73
75
};
74
76
77
+ struct isl68137_channel {
78
+ u32 vout_voltage_divider [2 ];
79
+ };
80
+
81
+ struct isl68137_data {
82
+ struct pmbus_driver_info info ;
83
+ struct isl68137_channel channel [MAX_CHANNELS ];
84
+ };
85
+
86
+ #define to_isl68137_data (x ) container_of(x, struct isl68137_data, info)
87
+
75
88
static const struct i2c_device_id raa_dmpvr_id [];
76
89
77
90
static ssize_t isl68137_avs_enable_show_page (struct i2c_client * client ,
@@ -163,13 +176,32 @@ static const struct attribute_group *isl68137_attribute_groups[] = {
163
176
static int raa_dmpvr2_read_word_data (struct i2c_client * client , int page ,
164
177
int phase , int reg )
165
178
{
179
+ const struct pmbus_driver_info * info = pmbus_get_driver_info (client );
180
+ const struct isl68137_data * data = to_isl68137_data (info );
166
181
int ret ;
182
+ u64 temp ;
167
183
168
184
switch (reg ) {
169
185
case PMBUS_VIRT_READ_VMON :
170
186
ret = pmbus_read_word_data (client , page , phase ,
171
187
RAA_DMPVR2_READ_VMON );
172
188
break ;
189
+ case PMBUS_READ_POUT :
190
+ case PMBUS_READ_VOUT :
191
+ /*
192
+ * In cases where a voltage divider is attached to the target
193
+ * rail between Vout and the Vsense pin, both Vout and Pout
194
+ * should be scaled by the voltage divider scaling factor.
195
+ * I.e. Vout = Vsense * Rtotal / Rout
196
+ */
197
+ ret = pmbus_read_word_data (client , page , phase , reg );
198
+ if (ret > 0 ) {
199
+ temp = DIV_U64_ROUND_CLOSEST ((u64 )ret *
200
+ data -> channel [page ].vout_voltage_divider [1 ],
201
+ data -> channel [page ].vout_voltage_divider [0 ]);
202
+ ret = clamp_val (temp , 0 , 0xffff );
203
+ }
204
+ break ;
173
205
default :
174
206
ret = - ENODATA ;
175
207
break ;
@@ -178,6 +210,40 @@ static int raa_dmpvr2_read_word_data(struct i2c_client *client, int page,
178
210
return ret ;
179
211
}
180
212
213
+ static int raa_dmpvr2_write_word_data (struct i2c_client * client , int page ,
214
+ int reg , u16 word )
215
+ {
216
+ const struct pmbus_driver_info * info = pmbus_get_driver_info (client );
217
+ const struct isl68137_data * data = to_isl68137_data (info );
218
+ int ret ;
219
+ u64 temp ;
220
+
221
+ switch (reg ) {
222
+ case PMBUS_VOUT_MAX :
223
+ case PMBUS_VOUT_MARGIN_HIGH :
224
+ case PMBUS_VOUT_MARGIN_LOW :
225
+ case PMBUS_VOUT_OV_FAULT_LIMIT :
226
+ case PMBUS_VOUT_UV_FAULT_LIMIT :
227
+ case PMBUS_VOUT_COMMAND :
228
+ /*
229
+ * In cases where a voltage divider is attached to the target
230
+ * rail between Vout and the Vsense pin, Vout related PMBus
231
+ * commands should be scaled based on the expected voltage
232
+ * at the Vsense pin.
233
+ * I.e. Vsense = Vout * Rout / Rtotal
234
+ */
235
+ temp = DIV_U64_ROUND_CLOSEST ((u64 )word *
236
+ data -> channel [page ].vout_voltage_divider [0 ],
237
+ data -> channel [page ].vout_voltage_divider [1 ]);
238
+ ret = clamp_val (temp , 0 , 0xffff );
239
+ break ;
240
+ default :
241
+ ret = - ENODATA ;
242
+ break ;
243
+ }
244
+ return ret ;
245
+ }
246
+
181
247
static struct pmbus_driver_info raa_dmpvr_info = {
182
248
.pages = 3 ,
183
249
.format [PSC_VOLTAGE_IN ] = direct ,
@@ -220,14 +286,90 @@ static struct pmbus_driver_info raa_dmpvr_info = {
220
286
| PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT ,
221
287
};
222
288
289
+ static int isl68137_probe_child_from_dt (struct device * dev ,
290
+ struct device_node * child ,
291
+ struct isl68137_data * data )
292
+ {
293
+ u32 channel , rout , rtotal ;
294
+ int err ;
295
+
296
+ err = of_property_read_u32 (child , "reg" , & channel );
297
+ if (err ) {
298
+ dev_err (dev , "missing reg property of %pOFn\n" , child );
299
+ return err ;
300
+ }
301
+ if (channel >= data -> info .pages ) {
302
+ dev_err (dev , "invalid reg %d of %pOFn\n" , channel , child );
303
+ return - EINVAL ;
304
+ }
305
+
306
+ err = of_property_read_u32_array (child , "vout-voltage-divider" ,
307
+ data -> channel [channel ].vout_voltage_divider ,
308
+ ARRAY_SIZE (data -> channel [channel ].vout_voltage_divider ));
309
+ if (err && err != - EINVAL ) {
310
+ dev_err (dev ,
311
+ "malformed vout-voltage-divider value for channel %d\n" ,
312
+ channel );
313
+ return err ;
314
+ }
315
+
316
+ rout = data -> channel [channel ].vout_voltage_divider [0 ];
317
+ rtotal = data -> channel [channel ].vout_voltage_divider [1 ];
318
+ if (rout == 0 ) {
319
+ dev_err (dev ,
320
+ "Voltage divider output resistance must be greater than 0\n" );
321
+ return - EINVAL ;
322
+ }
323
+ if (rtotal < rout ) {
324
+ dev_err (dev ,
325
+ "Voltage divider total resistance is less than output resistance\n" );
326
+ return - EINVAL ;
327
+ }
328
+
329
+ return 0 ;
330
+ }
331
+
332
+ static int isl68137_probe_from_dt (struct device * dev ,
333
+ struct isl68137_data * data )
334
+ {
335
+ const struct device_node * np = dev -> of_node ;
336
+ struct device_node * child ;
337
+ int err ;
338
+
339
+ for_each_child_of_node (np , child ) {
340
+ if (strcmp (child -> name , "channel" ))
341
+ continue ;
342
+
343
+ err = isl68137_probe_child_from_dt (dev , child , data );
344
+ if (err )
345
+ return err ;
346
+ }
347
+
348
+ return 0 ;
349
+ }
350
+
223
351
static int isl68137_probe (struct i2c_client * client )
224
352
{
353
+ struct device * dev = & client -> dev ;
225
354
struct pmbus_driver_info * info ;
355
+ struct isl68137_data * data ;
356
+ int i , err ;
226
357
227
- info = devm_kzalloc (& client -> dev , sizeof (* info ), GFP_KERNEL );
228
- if (!info )
358
+ data = devm_kzalloc (dev , sizeof (* data ), GFP_KERNEL );
359
+ if (!data )
229
360
return - ENOMEM ;
230
- memcpy (info , & raa_dmpvr_info , sizeof (* info ));
361
+
362
+ /*
363
+ * Initialize all voltage dividers to Rout=1 and Rtotal=1 to simplify
364
+ * logic in PMBus word read/write functions
365
+ */
366
+ for (i = 0 ; i < MAX_CHANNELS ; i ++ )
367
+ memset (data -> channel [i ].vout_voltage_divider ,
368
+ 1 ,
369
+ sizeof (data -> channel [i ].vout_voltage_divider ));
370
+
371
+ memcpy (& data -> info , & raa_dmpvr_info , sizeof (data -> info ));
372
+ info = & data -> info ;
231
373
232
374
switch (i2c_match_id (raa_dmpvr_id , client )-> driver_data ) {
233
375
case raa_dmpvr1_2rail :
@@ -237,11 +379,14 @@ static int isl68137_probe(struct i2c_client *client)
237
379
info -> func [1 ] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
238
380
| PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
239
381
| PMBUS_HAVE_POUT ;
382
+ info -> read_word_data = raa_dmpvr2_read_word_data ;
383
+ info -> write_word_data = raa_dmpvr2_write_word_data ;
240
384
info -> groups = isl68137_attribute_groups ;
241
385
break ;
242
386
case raa_dmpvr2_1rail :
243
387
info -> pages = 1 ;
244
388
info -> read_word_data = raa_dmpvr2_read_word_data ;
389
+ info -> write_word_data = raa_dmpvr2_write_word_data ;
245
390
break ;
246
391
case raa_dmpvr2_2rail_nontc :
247
392
info -> func [0 ] &= ~PMBUS_HAVE_TEMP3 ;
@@ -250,9 +395,11 @@ static int isl68137_probe(struct i2c_client *client)
250
395
case raa_dmpvr2_2rail :
251
396
info -> pages = 2 ;
252
397
info -> read_word_data = raa_dmpvr2_read_word_data ;
398
+ info -> write_word_data = raa_dmpvr2_write_word_data ;
253
399
break ;
254
400
case raa_dmpvr2_3rail :
255
401
info -> read_word_data = raa_dmpvr2_read_word_data ;
402
+ info -> write_word_data = raa_dmpvr2_write_word_data ;
256
403
break ;
257
404
case raa_dmpvr2_hv :
258
405
info -> pages = 1 ;
@@ -263,11 +410,16 @@ static int isl68137_probe(struct i2c_client *client)
263
410
info -> m [PSC_POWER ] = 2 ;
264
411
info -> R [PSC_POWER ] = -1 ;
265
412
info -> read_word_data = raa_dmpvr2_read_word_data ;
413
+ info -> write_word_data = raa_dmpvr2_write_word_data ;
266
414
break ;
267
415
default :
268
416
return - ENODEV ;
269
417
}
270
418
419
+ err = isl68137_probe_from_dt (dev , data );
420
+ if (err )
421
+ return err ;
422
+
271
423
return pmbus_do_probe (client , info );
272
424
}
273
425
@@ -318,11 +470,59 @@ static const struct i2c_device_id raa_dmpvr_id[] = {
318
470
319
471
MODULE_DEVICE_TABLE (i2c , raa_dmpvr_id );
320
472
473
+ static const struct of_device_id isl68137_of_match [] = {
474
+ { .compatible = "isil,isl68137" , .data = (void * )raa_dmpvr1_2rail },
475
+ { .compatible = "renesas,isl68220" , .data = (void * )raa_dmpvr2_2rail },
476
+ { .compatible = "renesas,isl68221" , .data = (void * )raa_dmpvr2_3rail },
477
+ { .compatible = "renesas,isl68222" , .data = (void * )raa_dmpvr2_2rail },
478
+ { .compatible = "renesas,isl68223" , .data = (void * )raa_dmpvr2_2rail },
479
+ { .compatible = "renesas,isl68224" , .data = (void * )raa_dmpvr2_3rail },
480
+ { .compatible = "renesas,isl68225" , .data = (void * )raa_dmpvr2_2rail },
481
+ { .compatible = "renesas,isl68226" , .data = (void * )raa_dmpvr2_3rail },
482
+ { .compatible = "renesas,isl68227" , .data = (void * )raa_dmpvr2_1rail },
483
+ { .compatible = "renesas,isl68229" , .data = (void * )raa_dmpvr2_3rail },
484
+ { .compatible = "renesas,isl68233" , .data = (void * )raa_dmpvr2_2rail },
485
+ { .compatible = "renesas,isl68239" , .data = (void * )raa_dmpvr2_3rail },
486
+
487
+ { .compatible = "renesas,isl69222" , .data = (void * )raa_dmpvr2_2rail },
488
+ { .compatible = "renesas,isl69223" , .data = (void * )raa_dmpvr2_3rail },
489
+ { .compatible = "renesas,isl69224" , .data = (void * )raa_dmpvr2_2rail },
490
+ { .compatible = "renesas,isl69225" , .data = (void * )raa_dmpvr2_2rail },
491
+ { .compatible = "renesas,isl69227" , .data = (void * )raa_dmpvr2_3rail },
492
+ { .compatible = "renesas,isl69228" , .data = (void * )raa_dmpvr2_3rail },
493
+ { .compatible = "renesas,isl69234" , .data = (void * )raa_dmpvr2_2rail },
494
+ { .compatible = "renesas,isl69236" , .data = (void * )raa_dmpvr2_2rail },
495
+ { .compatible = "renesas,isl69239" , .data = (void * )raa_dmpvr2_3rail },
496
+ { .compatible = "renesas,isl69242" , .data = (void * )raa_dmpvr2_2rail },
497
+ { .compatible = "renesas,isl69243" , .data = (void * )raa_dmpvr2_1rail },
498
+ { .compatible = "renesas,isl69247" , .data = (void * )raa_dmpvr2_2rail },
499
+ { .compatible = "renesas,isl69248" , .data = (void * )raa_dmpvr2_2rail },
500
+ { .compatible = "renesas,isl69254" , .data = (void * )raa_dmpvr2_2rail },
501
+ { .compatible = "renesas,isl69255" , .data = (void * )raa_dmpvr2_2rail },
502
+ { .compatible = "renesas,isl69256" , .data = (void * )raa_dmpvr2_2rail },
503
+ { .compatible = "renesas,isl69259" , .data = (void * )raa_dmpvr2_2rail },
504
+ { .compatible = "isil,isl69260" , .data = (void * )raa_dmpvr2_2rail },
505
+ { .compatible = "renesas,isl69268" , .data = (void * )raa_dmpvr2_2rail },
506
+ { .compatible = "isil,isl69269" , .data = (void * )raa_dmpvr2_3rail },
507
+ { .compatible = "renesas,isl69298" , .data = (void * )raa_dmpvr2_2rail },
508
+
509
+ { .compatible = "renesas,raa228000" , .data = (void * )raa_dmpvr2_hv },
510
+ { .compatible = "renesas,raa228004" , .data = (void * )raa_dmpvr2_hv },
511
+ { .compatible = "renesas,raa228006" , .data = (void * )raa_dmpvr2_hv },
512
+ { .compatible = "renesas,raa228228" , .data = (void * )raa_dmpvr2_2rail_nontc },
513
+ { .compatible = "renesas,raa229001" , .data = (void * )raa_dmpvr2_2rail },
514
+ { .compatible = "renesas,raa229004" , .data = (void * )raa_dmpvr2_2rail },
515
+ { },
516
+ };
517
+
518
+ MODULE_DEVICE_TABLE (of , isl68137_of_match );
519
+
321
520
/* This is the driver that will be inserted */
322
521
static struct i2c_driver isl68137_driver = {
323
522
.driver = {
324
- .name = "isl68137" ,
325
- },
523
+ .name = "isl68137" ,
524
+ .of_match_table = isl68137_of_match ,
525
+ },
326
526
.probe = isl68137_probe ,
327
527
.id_table = raa_dmpvr_id ,
328
528
};
0 commit comments