Hardware/LPC/IT87XX.cs
author moel.mich
Sat, 23 Jun 2012 22:14:28 +0000
changeset 353 b4e37f5b2669
parent 344 3145aadca3d2
child 382 ba6abd47a80c
permissions -rw-r--r--
Added support for IT8705F super I/O chips.
     1 /*
     2  
     3   This Source Code Form is subject to the terms of the Mozilla Public
     4   License, v. 2.0. If a copy of the MPL was not distributed with this
     5   file, You can obtain one at http://mozilla.org/MPL/2.0/.
     6  
     7   Copyright (C) 2009-2012 Michael Möller <mmoeller@openhardwaremonitor.org>
     8 	
     9 */
    10 
    11 using System.Globalization;
    12 using System.Text;
    13 
    14 namespace OpenHardwareMonitor.Hardware.LPC {
    15   internal class IT87XX : ISuperIO {
    16        
    17     private readonly ushort address;
    18     private readonly Chip chip;
    19     private readonly byte version;
    20 
    21     private readonly ushort gpioAddress;
    22     private readonly int gpioCount;
    23 
    24     private readonly ushort addressReg;
    25     private readonly ushort dataReg;
    26 
    27     private readonly float?[] voltages = new float?[0];
    28     private readonly float?[] temperatures = new float?[0];
    29     private readonly float?[] fans = new float?[0];
    30     private readonly float?[] controls = new float?[0];
    31 
    32     private readonly float voltageGain;
    33     private readonly bool has16bitFanCounter;
    34    
    35     // Consts
    36     private const byte ITE_VENDOR_ID = 0x90;
    37        
    38     // Environment Controller
    39     private const byte ADDRESS_REGISTER_OFFSET = 0x05;
    40     private const byte DATA_REGISTER_OFFSET = 0x06;
    41 
    42     // Environment Controller Registers    
    43     private const byte CONFIGURATION_REGISTER = 0x00;
    44     private const byte TEMPERATURE_BASE_REG = 0x29;
    45     private const byte VENDOR_ID_REGISTER = 0x58;
    46     private const byte FAN_TACHOMETER_DIVISOR_REGISTER = 0x0B;
    47     private readonly byte[] FAN_TACHOMETER_REG = 
    48       new byte[] { 0x0d, 0x0e, 0x0f, 0x80, 0x82 };
    49     private readonly byte[] FAN_TACHOMETER_EXT_REG =
    50       new byte[] { 0x18, 0x19, 0x1a, 0x81, 0x83 };
    51     private const byte VOLTAGE_BASE_REG = 0x20;
    52 
    53     private byte ReadByte(byte register, out bool valid) {
    54       Ring0.WriteIoPort(addressReg, register);
    55       byte value = Ring0.ReadIoPort(dataReg);
    56       valid = register == Ring0.ReadIoPort(addressReg);
    57       return value;
    58     }
    59 
    60     private bool WriteByte(byte register, byte value) {
    61       Ring0.WriteIoPort(addressReg, register);
    62       Ring0.WriteIoPort(dataReg, value);
    63       return register == Ring0.ReadIoPort(addressReg); 
    64     }
    65 
    66     public byte? ReadGPIO(int index) {
    67       if (index >= gpioCount)
    68         return null;
    69 
    70       return Ring0.ReadIoPort((ushort)(gpioAddress + index));
    71     }
    72 
    73     public void WriteGPIO(int index, byte value) {
    74       if (index >= gpioCount)
    75         return;
    76 
    77       Ring0.WriteIoPort((ushort)(gpioAddress + index), value);
    78     } 
    79 
    80     public void SetControl(int index, byte? value) { }   
    81 
    82     public IT87XX(Chip chip, ushort address, ushort gpioAddress, byte version) {
    83 
    84       this.address = address;
    85       this.chip = chip;
    86       this.version = version;
    87       this.addressReg = (ushort)(address + ADDRESS_REGISTER_OFFSET);
    88       this.dataReg = (ushort)(address + DATA_REGISTER_OFFSET);
    89       this.gpioAddress = gpioAddress;
    90 
    91       // Check vendor id
    92       bool valid;
    93       byte vendorId = ReadByte(VENDOR_ID_REGISTER, out valid);       
    94       if (!valid || vendorId != ITE_VENDOR_ID)
    95         return;
    96 
    97       // Bit 0x10 of the configuration register should always be 1
    98       if ((ReadByte(CONFIGURATION_REGISTER, out valid) & 0x10) == 0)
    99         return;
   100       if (!valid)
   101         return;
   102 
   103       voltages = new float?[9];
   104       temperatures = new float?[3];
   105       fans = new float?[chip == Chip.IT8705F ? 3 : 5];
   106 
   107       // IT8721F, IT8728F and IT8772E use a 12mV resultion ADC, all others 16mV
   108       if (chip == Chip.IT8721F || chip == Chip.IT8728F || chip == Chip.IT8771E 
   109         || chip == Chip.IT8772E) 
   110       {
   111         voltageGain = 0.012f;
   112       } else {
   113         voltageGain = 0.016f;        
   114       }
   115 
   116       // older IT8705F and IT8721F revisions do not have 16-bit fan counters
   117       if ((chip == Chip.IT8705F && version < 3) || 
   118           (chip == Chip.IT8712F && version < 8)) 
   119       {
   120         has16bitFanCounter = false;
   121       } else {
   122         has16bitFanCounter = true;
   123       }
   124 
   125       // Set the number of GPIO sets
   126       switch (chip) {
   127         case Chip.IT8712F:
   128         case Chip.IT8716F:
   129         case Chip.IT8718F:
   130         case Chip.IT8726F:
   131           gpioCount = 5;
   132           break;
   133         case Chip.IT8720F:
   134         case Chip.IT8721F:
   135           gpioCount = 8;
   136           break;
   137         case Chip.IT8705F: 
   138         case Chip.IT8728F:
   139         case Chip.IT8771E:
   140         case Chip.IT8772E:
   141           gpioCount = 0;
   142           break;
   143       }
   144     }
   145 
   146     public Chip Chip { get { return chip; } }
   147     public float?[] Voltages { get { return voltages; } }
   148     public float?[] Temperatures { get { return temperatures; } }
   149     public float?[] Fans { get { return fans; } }
   150     public float?[] Controls { get { return controls; } }
   151 
   152     public string GetReport() {
   153       StringBuilder r = new StringBuilder();
   154 
   155       r.AppendLine("LPC " + this.GetType().Name);
   156       r.AppendLine();
   157       r.Append("Chip ID: 0x"); r.AppendLine(chip.ToString("X"));
   158       r.Append("Chip Version: 0x"); r.AppendLine(
   159         version.ToString("X", CultureInfo.InvariantCulture));
   160       r.Append("Base Address: 0x"); r.AppendLine(
   161         address.ToString("X4", CultureInfo.InvariantCulture));
   162       r.Append("GPIO Address: 0x"); r.AppendLine(
   163         gpioAddress.ToString("X4", CultureInfo.InvariantCulture));
   164       r.AppendLine();
   165 
   166       if (!Ring0.WaitIsaBusMutex(100))
   167         return r.ToString();
   168 
   169       r.AppendLine("Environment Controller Registers");
   170       r.AppendLine();
   171       r.AppendLine("      00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
   172       r.AppendLine();
   173       for (int i = 0; i <= 0xA; i++) {
   174         r.Append(" "); 
   175         r.Append((i << 4).ToString("X2", CultureInfo.InvariantCulture)); 
   176         r.Append("  ");
   177         for (int j = 0; j <= 0xF; j++) {
   178           r.Append(" ");
   179           bool valid;
   180           byte value = ReadByte((byte)((i << 4) | j), out valid);
   181           r.Append(
   182             valid ? value.ToString("X2", CultureInfo.InvariantCulture) : "??");
   183         }
   184         r.AppendLine();
   185       }
   186       r.AppendLine();
   187 
   188       r.AppendLine("GPIO Registers");
   189       r.AppendLine();
   190       for (int i = 0; i < gpioCount; i++) {
   191         r.Append(" ");
   192         r.Append(ReadGPIO(i).Value.ToString("X2",
   193           CultureInfo.InvariantCulture));
   194       }
   195       r.AppendLine();
   196       r.AppendLine();
   197 
   198       Ring0.ReleaseIsaBusMutex();
   199 
   200       return r.ToString();
   201     }
   202 
   203     public void Update() {
   204       if (!Ring0.WaitIsaBusMutex(10))
   205         return;
   206 
   207       for (int i = 0; i < voltages.Length; i++) {
   208         bool valid;
   209         
   210         float value = 
   211           voltageGain * ReadByte((byte)(VOLTAGE_BASE_REG + i), out valid);   
   212 
   213         if (!valid)
   214           continue;
   215         if (value > 0)
   216           voltages[i] = value;  
   217         else
   218           voltages[i] = null;
   219       }
   220 
   221       for (int i = 0; i < temperatures.Length; i++) {
   222         bool valid;
   223         sbyte value = (sbyte)ReadByte(
   224           (byte)(TEMPERATURE_BASE_REG + i), out valid);
   225         if (!valid)
   226           continue;
   227 
   228         if (value < sbyte.MaxValue && value > 0)
   229           temperatures[i] = value;
   230         else
   231           temperatures[i] = null;       
   232       }
   233 
   234       if (has16bitFanCounter) {
   235         for (int i = 0; i < fans.Length; i++) {
   236           bool valid;
   237           int value = ReadByte(FAN_TACHOMETER_REG[i], out valid);
   238           if (!valid)
   239             continue;
   240           value |= ReadByte(FAN_TACHOMETER_EXT_REG[i], out valid) << 8;
   241           if (!valid)
   242             continue;
   243 
   244           if (value > 0x3f) {
   245             fans[i] = (value < 0xffff) ? 1.35e6f / (value * 2) : 0;
   246           } else {
   247             fans[i] = null;
   248           }
   249         }
   250       } else {
   251         for (int i = 0; i < fans.Length; i++) {
   252           bool valid;
   253           int value = ReadByte(FAN_TACHOMETER_REG[i], out valid);
   254           if (!valid)
   255             continue;
   256 
   257           int divisor = 2;
   258           if (i < 2) {
   259             int divisors = ReadByte(FAN_TACHOMETER_DIVISOR_REGISTER, out valid);
   260             if (!valid)
   261               continue;
   262             divisor = 1 << ((divisors >> (3 * i)) & 0x7);
   263           }
   264 
   265           if (value > 0) {
   266             fans[i] = (value < 0xff) ? 1.35e6f / (value * divisor) : 0;
   267           } else {
   268             fans[i] = null;
   269           }
   270         }
   271       }
   272 
   273       Ring0.ReleaseIsaBusMutex();
   274     }
   275   } 
   276 }