<font size=2 face="sans-serif">What makes this pull request different
from other openbmc changes to require to be sent via git-send-email before
it can be reviewed?</font><br><br><br><br><br><br><br><font size=1 color=#5f5f5f face="sans-serif">From:      
 </font><font size=1 face="sans-serif">Joel Stanley <joel@jms.id.au></font><br><font size=1 color=#5f5f5f face="sans-serif">To:      
 </font><font size=1 face="sans-serif">OpenBMC Patches <openbmc-patches@stwcx.xyz></font><br><font size=1 color=#5f5f5f face="sans-serif">Cc:      
 </font><font size=1 face="sans-serif">OpenBMC Maillist <openbmc@lists.ozlabs.org></font><br><font size=1 color=#5f5f5f face="sans-serif">Date:      
 </font><font size=1 face="sans-serif">02/17/2016 10:24 PM</font><br><font size=1 color=#5f5f5f face="sans-serif">Subject:    
   </font><font size=1 face="sans-serif">Re: [PATCH openbmc]
Add temporary adm1278 hwmon pmbus driver patch</font><br><font size=1 color=#5f5f5f face="sans-serif">Sent by:    
   </font><font size=1 face="sans-serif">"openbmc"
<openbmc-bounces+anoo=us.ibm.com@lists.ozlabs.org></font><br><hr noshade><br><br><br><tt><font size=2>On Wed, Feb 17, 2016 at 9:00 PM, OpenBMC Patches<br><openbmc-patches@stwcx.xyz> wrote:<br>> From: Yi Li <adamliyi@msn.com><br>><br>> This patch temporarily adds adm1278 hwmon driver as a kernel patch
to openbmc,<br>> for testing on Barreleye.<br><br>Can you please send this as a patch with git-send-email so we can review
it.<br><br>> If in the future this patch will still be useful, it should be put
into linux kernel.<br>><br>> Barreleye has three adm1278 devices on three i2c buses.<br>> This patch enables reading adm1278 sensors via hwmon sysfs interface.<br>> The enabled sensors are: current, voltage (In and Out), power and
temperature.<br>> Detail usage can be found in 'readme_adm1278.txt'.<br>><br>> Signed-off-by: Yi Li <adamliyi@msn.com><br>> ---<br>>  .../recipes-kernel/linux/linux-obmc/barreleye.cfg  |  
3 +<br>>  .../linux/linux-obmc/hwmon_adm1278.patch      
    | 165 +++++++++++++++++++++<br>>  .../linux/linux-obmc/readme_adm1278.txt      
     |  78 ++++++++++<br>>  .../recipes-kernel/linux/linux-obmc_%.bbappend    
|   3 +<br>>  4 files changed, 249 insertions(+)<br>>  create mode 100644 meta-openbmc-machines/meta-openpower/meta-rackspace/meta-barreleye/recipes-kernel/linux/linux-obmc/barreleye.cfg<br>>  create mode 100644 meta-openbmc-machines/meta-openpower/meta-rackspace/meta-barreleye/recipes-kernel/linux/linux-obmc/hwmon_adm1278.patch<br>>  create mode 100644 meta-openbmc-machines/meta-openpower/meta-rackspace/meta-barreleye/recipes-kernel/linux/linux-obmc/readme_adm1278.txt<br>>  create mode 100644 meta-openbmc-machines/meta-openpower/meta-rackspace/meta-barreleye/recipes-kernel/linux/linux-obmc_%.bbappend<br>><br>> diff --git a/meta-openbmc-machines/meta-openpower/meta-rackspace/meta-barreleye/recipes-kernel/linux/linux-obmc/barreleye.cfg
b/meta-openbmc-machines/meta-openpower/meta-rackspace/meta-barreleye/recipes-kernel/linux/linux-obmc/barreleye.cfg<br>> new file mode 100644<br>> index 0000000..086f191<br>> --- /dev/null<br>> +++ b/meta-openbmc-machines/meta-openpower/meta-rackspace/meta-barreleye/recipes-kernel/linux/linux-obmc/barreleye.cfg<br>> @@ -0,0 +1,3 @@<br>> +CONFIG_PMBUS=y<br>> +CONFIG_SENSORS_PMBUS=y<br>> +CONFIG_SENSORS_ADM1275=y<br>> diff --git a/meta-openbmc-machines/meta-openpower/meta-rackspace/meta-barreleye/recipes-kernel/linux/linux-obmc/hwmon_adm1278.patch
b/meta-openbmc-machines/meta-openpower/meta-rackspace/meta-barreleye/recipes-kernel/linux/linux-obmc/hwmon_adm1278.patch<br>> new file mode 100644<br>> index 0000000..074d39f<br>> --- /dev/null<br>> +++ b/meta-openbmc-machines/meta-openpower/meta-rackspace/meta-barreleye/recipes-kernel/linux/linux-obmc/hwmon_adm1278.patch<br>> @@ -0,0 +1,165 @@<br>> +diff --git a/drivers/hwmon/pmbus/adm1275.c b/drivers/hwmon/pmbus/adm1275.c<br>> +index 188af4c..a45075d 100644<br>> +--- a/drivers/hwmon/pmbus/adm1275.c<br>> ++++ b/drivers/hwmon/pmbus/adm1275.c<br>> +@@ -24,7 +24,7 @@<br>> + #include <linux/bitops.h><br>> + #include "pmbus.h"<br>> +<br>> +-enum chips { adm1075, adm1275, adm1276, adm1293, adm1294 };<br>> ++enum chips { adm1075, adm1275, adm1276, adm1278, adm1293, adm1294
};<br>> +<br>> + #define ADM1275_MFR_STATUS_IOUT_WARN2 BIT(0)<br>> + #define ADM1293_MFR_STATUS_VAUX_UV_WARN       BIT(5)<br>> +@@ -70,6 +70,22 @@ enum chips { adm1075, adm1275, adm1276, adm1293,
adm1294 };<br>> + #define ADM1075_VAUX_OV_WARN          BIT(7)<br>> + #define ADM1075_VAUX_UV_WARN          BIT(6)<br>> +<br>> ++#define ADM1278_PMON_CONTROL          0xd3<br>> ++#define ADM1278_PMON_CONFIG           0xd4<br>> ++#define ADM1278_CFG_TSFLT            
BIT(15)<br>> ++#define ADM1278_CFG_SIMULTANEOUS      BIT(14)<br>> ++#define ADM1278_CFG_PMON_MODE         BIT(4)<br>> ++#define ADM1278_CFG_TEMP1_EN          BIT(3)<br>> ++#define ADM1278_CFG_VIN_EN            BIT(2)<br>> ++#define ADM1278_CFG_VOUT_EN           BIT(1)<br>> ++#define ADM1278_PEAK_TEMPERATURE      0xd7<br>> ++<br>> ++#define ADM1278_R_SENSE       1000    /*
R_sense resistor value in microohmsi */<br>> ++<br>> ++static int r_sense = ADM1278_R_SENSE;<br>> ++module_param(r_sense, int, 0644);<br>> ++MODULE_PARM_DESC(r_sense, "Rsense resistor value in microohms");<br>> ++<br>> + struct adm1275_data {<br>> +       int id;<br>> +       bool have_oc_fault;<br>> +@@ -186,6 +202,11 @@ static int adm1275_read_word_data(struct i2c_client
*client, int page, int reg)<br>> +       case PMBUS_VIRT_READ_VIN_MAX:<br>> +               ret = pmbus_read_word_data(client,
0, ADM1275_PEAK_VIN);<br>> +               break;<br>> ++      case PMBUS_VIRT_READ_TEMP_MAX:<br>> ++              if (data->id
!= adm1278)<br>> ++                  
   return -ENODATA;<br>> ++              ret = pmbus_read_word_data(client,
0, ADM1278_PEAK_TEMPERATURE);<br>> ++              break;<br>> +       case PMBUS_VIRT_READ_PIN_MIN:<br>> +               if (!data->have_pin_min)<br>> +                    
  return -ENXIO;<br>> +@@ -199,6 +220,7 @@ static int adm1275_read_word_data(struct i2c_client
*client, int page, int reg)<br>> +       case PMBUS_VIRT_RESET_IOUT_HISTORY:<br>> +       case PMBUS_VIRT_RESET_VOUT_HISTORY:<br>> +       case PMBUS_VIRT_RESET_VIN_HISTORY:<br>> ++      case PMBUS_VIRT_RESET_TEMP_HISTORY:<br>> +               break;<br>> +       case PMBUS_VIRT_RESET_PIN_HISTORY:<br>> +               if (!data->have_pin_max)<br>> +@@ -239,6 +261,9 @@ static int adm1275_write_word_data(struct i2c_client
*client, int page, int reg,<br>> +       case PMBUS_VIRT_RESET_VIN_HISTORY:<br>> +               ret = pmbus_write_word_data(client,
0, ADM1275_PEAK_VIN, 0);<br>> +               break;<br>> ++      case PMBUS_VIRT_RESET_TEMP_HISTORY:<br>> ++              ret = pmbus_write_word_data(client,
0, ADM1278_PEAK_TEMPERATURE, 0);<br>> ++              break;<br>> +       case PMBUS_VIRT_RESET_PIN_HISTORY:<br>> +               ret = pmbus_write_word_data(client,
0, ADM1276_PEAK_PIN, 0);<br>> +               if (!ret &&
data->have_pin_min)<br>> +@@ -312,6 +337,7 @@ static const struct i2c_device_id adm1275_id[]
= {<br>> +       { "adm1075", adm1075 },<br>> +       { "adm1275", adm1275 },<br>> +       { "adm1276", adm1276 },<br>> ++      { "adm1278", adm1278 },<br>> +       { "adm1293", adm1293 },<br>> +       { "adm1294", adm1294 },<br>> +       { }<br>> +@@ -335,6 +361,8 @@ static int adm1275_probe(struct i2c_client *client,<br>> +                    
               | I2C_FUNC_SMBUS_BLOCK_DATA))<br>> +               return -ENODEV;<br>> +<br>> ++      /* i2c_aspeed driver does not handle i2c_smbus_read_block_data
correctly */<br>> ++#if 0<br>> +       ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID,
block_buffer);<br>> +       if (ret < 0) {<br>> +               dev_err(&client->dev,
"Failed to read Manufacturer ID\n");<br>> +@@ -363,6 +391,7 @@ static int adm1275_probe(struct i2c_client *client,<br>> +               dev_notice(&client->dev,<br>> +                    
     "Device mismatch: Configured %s, detected %s\n",<br>> +                    
     id->name, mid->name);<br>> ++#endif<br>> +<br>> +       config = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG);<br>> +       if (config < 0)<br>> +@@ -377,7 +406,9 @@ static int adm1275_probe(struct i2c_client *client,<br>> +       if (!data)<br>> +               return -ENOMEM;<br>> +<br>> +-      data->id = mid->driver_data;<br>> ++      /* i2c_aspeed driver does not handle i2c_smbus_read_block_data
correctly */<br>> ++      //data->id = mid->driver_data;<br>> ++      data->id = adm1278;<br>> +<br>> +       info = &data->info;<br>> +<br>> +@@ -460,6 +491,62 @@ static int adm1275_probe(struct i2c_client *client,<br>> +                    
  info->func[0] |=<br>> +                    
    PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;<br>> +               break;<br>> ++      case adm1278:<br>> ++              /* Configure monitoring
*/<br>> ++              ret = i2c_smbus_write_byte_data(client,<br>> ++                  
   ADM1278_PMON_CONTROL, 0);<br>> ++              if (ret < 0)<br>> ++                  
   return ret;<br>> ++              ret = i2c_smbus_read_word_data(client,
ADM1275_PMON_CONFIG);<br>> ++              ret = i2c_smbus_write_word_data(client,
ADM1275_PMON_CONFIG,<br>> ++                  
                     
     ADM1278_CFG_PMON_MODE |<br>> ++                  
                     
     ADM1278_CFG_TEMP1_EN |<br>> ++                  
                     
     ADM1278_CFG_VIN_EN |<br>> ++                  
                     
     ADM1278_CFG_VOUT_EN);<br>> ++              if (ret < 0)<br>> ++                  
   return ret;<br>> ++              ret = i2c_smbus_read_word_data(client,
ADM1275_PMON_CONFIG);<br>> ++              dev_info(&client->dev,
"adm1278 config: 0x%x\n", ret);<br>> ++              ret = i2c_smbus_write_byte_data(client,
ADM1278_PMON_CONTROL,1);<br>> ++              if (ret < 0)<br>> ++                  
   return ret;<br>> ++<br>> ++              info->func[0]
|= PMBUS_HAVE_VIN<br>> ++                  
   | PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT<br>> ++                  
   | PMBUS_HAVE_PIN<br>> ++                  
   | PMBUS_HAVE_STATUS_INPUT<br>> ++                  
   | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;<br>> ++<br>> ++              data->have_oc_fault
= false;<br>> ++              data->have_uc_fault
= false;<br>> ++              data->have_vout
= true;<br>> ++              data->have_vaux_status
= false;<br>> ++              data->have_mfr_vaux_status
= false;<br>> ++              data->have_iout_min
= false;<br>> ++              data->have_pin_min
= false;<br>> ++              data->have_pin_max
= true;<br>> ++<br>> ++              info->m[PSC_VOLTAGE_IN]
= 19599;<br>> ++              info->b[PSC_VOLTAGE_IN]
= 0;<br>> ++              info->R[PSC_VOLTAGE_IN]
= -2;<br>> ++<br>> ++              info->m[PSC_VOLTAGE_OUT]
= 19599;<br>> ++              info->b[PSC_VOLTAGE_OUT]
= 0;<br>> ++              info->R[PSC_VOLTAGE_OUT]
= -2;<br>> ++<br>> ++              info->m[PSC_CURRENT_OUT]
= 800 * r_sense / 1000;<br>> ++              info->b[PSC_CURRENT_OUT]
= 20475;<br>> ++              info->R[PSC_CURRENT_OUT]
= -1;<br>> ++<br>> ++              info->m[PSC_POWER]
= 6123 * r_sense / 1000;<br>> ++              info->b[PSC_POWER]
= 0;<br>> ++              info->R[PSC_POWER]
= -2;<br>> ++<br>> ++              info->format[PSC_TEMPERATURE]
= direct;<br>> ++              info->m[PSC_TEMPERATURE]
= 42;<br>> ++              info->b[PSC_TEMPERATURE]
= 31880;<br>> ++              info->R[PSC_TEMPERATURE]
= -1;<br>> ++              break;<br>> +       case adm1293:<br>> +       case adm1294:<br>> +               data->have_iout_min
= true;<br>> diff --git a/meta-openbmc-machines/meta-openpower/meta-rackspace/meta-barreleye/recipes-kernel/linux/linux-obmc/readme_adm1278.txt
b/meta-openbmc-machines/meta-openpower/meta-rackspace/meta-barreleye/recipes-kernel/linux/linux-obmc/readme_adm1278.txt<br>> new file mode 100644<br>> index 0000000..e86d977<br>> --- /dev/null<br>> +++ b/meta-openbmc-machines/meta-openpower/meta-rackspace/meta-barreleye/recipes-kernel/linux/linux-obmc/readme_adm1278.txt<br>> @@ -0,0 +1,78 @@<br>> +README for adm1278 hwmon driver<br>> +==================================<br>> +Yi Li <shliyi@cn.ibm.com><br>> +<br>> +<br>> +This is a temporary kernel patch to enable hwmon driver for adm1278
chip on Barreleye.<br>> +When this patch is merged into linux kernel, this patch will be removed
from openbmc.<br>> +<br>> +The adm1278 driver is created according to datasheet:<br>> +http://www.analog.com/media/en/technical-documentation/data-sheets/ADM1278.pdf<br>> +<br>> +The patch heavily re-used adm1278 enabling code from: </font></tt><a href="https://github.com/facebook/openbmc/blob/master/meta-aspeed/recipes-kernel/linux/files/patch-2.6.28.9/0000-linux-openbmc.patch"><tt><font size=2>https://github.com/facebook/openbmc/blob/master/meta-aspeed/recipes-kernel/linux/files/patch-2.6.28.9/0000-linux-openbmc.patch</font></tt></a><tt><font size=2>.<br>> +<br>> +This patch has been tested on barreleye, by following these steps:<br>> +<br>> +1) There are 3 adm1278 devices on Barreleye<br>> +<br>> +I2C5: P12v_a for CPU0<br>> +I2C6: P12v_b for CPU1<br>> +I2C7: P12v_c for HDD and IO Board<br>> +<br>> +2) adm1278 driver is based on adm1275.c, which depends on pmbus.
This patch builds<br>> +adm1275 and pmbus into kernel.<br>> +<br>> +3) When kernel booted, initialize the adm1278 devices:<br>> +<br>> +root@barreleye:~# echo adm1278 0x10 > /sys/class/i2c-adapter/i2c-4/new_device<br>> +root@barreleye:~# echo adm1278 0x10 > /sys/class/i2c-adapter/i2c-5/new_device<br>> +root@barreleye:~# echo adm1278 0x10 > /sys/class/i2c-adapter/i2c-6/new_device<br>> +<br>> +There will be three new hwmon sysfs entries created:<br>> +<br>> +root@barreleye:~# ls /sys/class/hwmon/hwmon3/<br>> +curr1_highest         in1_highest    
      in1_reset_history     in2_min_alarm  
      power1_label          temp1_input<br>> +curr1_input           in1_input    
        in2_highest          
in2_reset_history     power1_max        
   temp1_max<br>> +curr1_label           in1_label    
        in2_input          
  name                  power1_reset_history
 temp1_max_alarm<br>> +curr1_max             in1_max  
            in2_label      
      power/              
 subsystem/            temp1_reset_history<br>> +curr1_max_alarm       in1_max_alarm    
    in2_max              
power1_alarm          temp1_crit    
       uevent<br>> +curr1_reset_history   in1_min          
    in2_max_alarm         power1_input  
       temp1_crit_alarm<br>> +device/               in1_min_alarm
        in2_min          
    power1_input_highest  temp1_highest<br>> +root@barreleye:~# ls /sys/class/hwmon/hwmon4/<br>> +curr1_highest         in1_highest    
      in1_reset_history     in2_min_alarm  
      power1_label          temp1_input<br>> +curr1_input           in1_input    
        in2_highest          
in2_reset_history     power1_max        
   temp1_max<br>> +curr1_label           in1_label    
        in2_input          
  name                  power1_reset_history
 temp1_max_alarm<br>> +curr1_max             in1_max  
            in2_label      
      power/              
 subsystem/            temp1_reset_history<br>> +curr1_max_alarm       in1_max_alarm    
    in2_max              
power1_alarm          temp1_crit    
       uevent<br>> +curr1_reset_history   in1_min          
    in2_max_alarm         power1_input  
       temp1_crit_alarm<br>> +device/               in1_min_alarm
        in2_min          
    power1_input_highest  temp1_highest<br>> +root@barreleye:~# ls /sys/class/hwmon/hwmon5/<br>> +curr1_highest         in1_highest    
      in1_reset_history     in2_min_alarm  
      power1_label          temp1_input<br>> +curr1_input           in1_input    
        in2_highest          
in2_reset_history     power1_max        
   temp1_max<br>> +curr1_label           in1_label    
        in2_input          
  name                  power1_reset_history
 temp1_max_alarm<br>> +curr1_max             in1_max  
            in2_label      
      power/              
 subsystem/            temp1_reset_history<br>> +curr1_max_alarm       in1_max_alarm    
    in2_max              
power1_alarm          temp1_crit    
       uevent<br>> +curr1_reset_history   in1_min          
    in2_max_alarm         power1_input  
       temp1_crit_alarm<br>> +device/               in1_min_alarm
        in2_min          
    power1_input_highest  temp1_highest<br>> +<br>> +4) For details of what each hwmon sysfs attributes mean, please refer
to:<br>> +https://www.kernel.org/doc/Documentation/hwmon/pmbus<br>> +For short, 'curr1_*' refers to 'IOUT', 'in1_*' refers to 'vin', 'in2_*'
refers to 'vout', 'power1_*' refers to 'input power',<br>> +'temp1_*' for 'temperature'.<br>> +<br>> +5) Remaining issue:<br>> +<br>> +5.1) Currently, i2c_aspeed driver does not handle "i2c_smbus_read_block_data()"
correctly. So this patch has to bypass some detection code.<br>> +We need to fix this issue when the patch is merged to kernel.<br>> +5.2) According to adm1278 datasheet, there is a sense resistor used
to measure power and current. The resistor will affect conversion between<br>> +adm1278 register value to real-world value for current and power.
I am not very sure about the resistor value. So using 1 mili-ohms (or 1000
micro-ohms) as default value. When build the adm1275 driver as kernel module,
we can set this resistor value by:<br>> +<br>> +# insmod adm1275.ko r_sense=500<br>> +<br>> +This will set the 'sense resistor' to 500 micro-ohms.<br>> +5.3) Some of the sensor value, e.g, 'temp1_input' seems not reasonable,
e.g:<br>> +<br>> +root@barreleye:~# cat /sys/class/hwmon/hwmon4/temp1_input<br>> +-270952<br>> +<br>> +Need further check on that.<br>> diff --git a/meta-openbmc-machines/meta-openpower/meta-rackspace/meta-barreleye/recipes-kernel/linux/linux-obmc_%.bbappend
b/meta-openbmc-machines/meta-openpower/meta-rackspace/meta-barreleye/recipes-kernel/linux/linux-obmc_%.bbappend<br>> new file mode 100644<br>> index 0000000..b6e8e16<br>> --- /dev/null<br>> +++ b/meta-openbmc-machines/meta-openpower/meta-rackspace/meta-barreleye/recipes-kernel/linux/linux-obmc_%.bbappend<br>> @@ -0,0 +1,3 @@<br>> +FILESEXTRAPATHS_prepend := "${THISDIR}/linux-obmc:"<br>> +SRC_URI += "</font></tt><a href=file://barreleye.cfgfg/><tt><font size=2>file://barreleye.cfg</font></tt></a><tt><font size=2>"<br>> +SRC_URI += "</font></tt><a href=file://hwmon_adm1278.patchch/><tt><font size=2>file://hwmon_adm1278.patch</font></tt></a><tt><font size=2>"<br>> --<br>> 2.7.1<br>><br>><br>> _______________________________________________<br>> openbmc mailing list<br>> openbmc@lists.ozlabs.org<br>> </font></tt><a href=https://lists.ozlabs.org/listinfo/openbmc><tt><font size=2>https://lists.ozlabs.org/listinfo/openbmc</font></tt></a><tt><font size=2><br>_______________________________________________<br>openbmc mailing list<br>openbmc@lists.ozlabs.org<br></font></tt><a href=https://lists.ozlabs.org/listinfo/openbmc><tt><font size=2>https://lists.ozlabs.org/listinfo/openbmc</font></tt></a><tt><font size=2><br></font></tt><br><br><BR>