1313#include <linux/init.h>
1414#include <linux/kernel.h>
1515#include <linux/module.h>
16+ #include <linux/of.h>
1617#include <linux/string.h>
1718#include <linux/sysfs.h>
1819
1920#include "pmbus.h"
2021
2122#define ISL68137_VOUT_AVS 0x30
2223#define RAA_DMPVR2_READ_VMON 0xc8
24+ #define MAX_CHANNELS 4
2325
2426enum chips {
2527 isl68137 ,
@@ -72,6 +74,17 @@ enum variants {
7274 raa_dmpvr2_hv ,
7375};
7476
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+
7588static const struct i2c_device_id raa_dmpvr_id [];
7689
7790static ssize_t isl68137_avs_enable_show_page (struct i2c_client * client ,
@@ -163,13 +176,32 @@ static const struct attribute_group *isl68137_attribute_groups[] = {
163176static int raa_dmpvr2_read_word_data (struct i2c_client * client , int page ,
164177 int phase , int reg )
165178{
179+ const struct pmbus_driver_info * info = pmbus_get_driver_info (client );
180+ const struct isl68137_data * data = to_isl68137_data (info );
166181 int ret ;
182+ u64 temp ;
167183
168184 switch (reg ) {
169185 case PMBUS_VIRT_READ_VMON :
170186 ret = pmbus_read_word_data (client , page , phase ,
171187 RAA_DMPVR2_READ_VMON );
172188 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 ;
173205 default :
174206 ret = - ENODATA ;
175207 break ;
@@ -178,6 +210,40 @@ static int raa_dmpvr2_read_word_data(struct i2c_client *client, int page,
178210 return ret ;
179211}
180212
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+
181247static struct pmbus_driver_info raa_dmpvr_info = {
182248 .pages = 3 ,
183249 .format [PSC_VOLTAGE_IN ] = direct ,
@@ -220,14 +286,90 @@ static struct pmbus_driver_info raa_dmpvr_info = {
220286 | PMBUS_HAVE_STATUS_IOUT | PMBUS_HAVE_POUT ,
221287};
222288
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+
223351static int isl68137_probe (struct i2c_client * client )
224352{
353+ struct device * dev = & client -> dev ;
225354 struct pmbus_driver_info * info ;
355+ struct isl68137_data * data ;
356+ int i , err ;
226357
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 )
229360 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 ;
231373
232374 switch (i2c_match_id (raa_dmpvr_id , client )-> driver_data ) {
233375 case raa_dmpvr1_2rail :
@@ -237,11 +379,14 @@ static int isl68137_probe(struct i2c_client *client)
237379 info -> func [1 ] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT
238380 | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT
239381 | PMBUS_HAVE_POUT ;
382+ info -> read_word_data = raa_dmpvr2_read_word_data ;
383+ info -> write_word_data = raa_dmpvr2_write_word_data ;
240384 info -> groups = isl68137_attribute_groups ;
241385 break ;
242386 case raa_dmpvr2_1rail :
243387 info -> pages = 1 ;
244388 info -> read_word_data = raa_dmpvr2_read_word_data ;
389+ info -> write_word_data = raa_dmpvr2_write_word_data ;
245390 break ;
246391 case raa_dmpvr2_2rail_nontc :
247392 info -> func [0 ] &= ~PMBUS_HAVE_TEMP3 ;
@@ -250,9 +395,11 @@ static int isl68137_probe(struct i2c_client *client)
250395 case raa_dmpvr2_2rail :
251396 info -> pages = 2 ;
252397 info -> read_word_data = raa_dmpvr2_read_word_data ;
398+ info -> write_word_data = raa_dmpvr2_write_word_data ;
253399 break ;
254400 case raa_dmpvr2_3rail :
255401 info -> read_word_data = raa_dmpvr2_read_word_data ;
402+ info -> write_word_data = raa_dmpvr2_write_word_data ;
256403 break ;
257404 case raa_dmpvr2_hv :
258405 info -> pages = 1 ;
@@ -263,11 +410,16 @@ static int isl68137_probe(struct i2c_client *client)
263410 info -> m [PSC_POWER ] = 2 ;
264411 info -> R [PSC_POWER ] = -1 ;
265412 info -> read_word_data = raa_dmpvr2_read_word_data ;
413+ info -> write_word_data = raa_dmpvr2_write_word_data ;
266414 break ;
267415 default :
268416 return - ENODEV ;
269417 }
270418
419+ err = isl68137_probe_from_dt (dev , data );
420+ if (err )
421+ return err ;
422+
271423 return pmbus_do_probe (client , info );
272424}
273425
@@ -318,11 +470,59 @@ static const struct i2c_device_id raa_dmpvr_id[] = {
318470
319471MODULE_DEVICE_TABLE (i2c , raa_dmpvr_id );
320472
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+
321520/* This is the driver that will be inserted */
322521static struct i2c_driver isl68137_driver = {
323522 .driver = {
324- .name = "isl68137" ,
325- },
523+ .name = "isl68137" ,
524+ .of_match_table = isl68137_of_match ,
525+ },
326526 .probe = isl68137_probe ,
327527 .id_table = raa_dmpvr_id ,
328528};
0 commit comments