Hardware/LPC/IT87XX.cs
author moel.mich
Fri, 22 Jun 2012 10:05:23 +0000
changeset 352 0899f651d5cf
parent 341 5172a92c5c20
child 353 b4e37f5b2669
permissions -rw-r--r--
Integrated the patch for Fintek F71808E super I/O support developed by Andrey Mushatov.
     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?[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 IT8721F revision do not have 16-bit fan counters
   117       if (chip == Chip.IT8712F && version < 8) {
   118         has16bitFanCounter = false;
   119       } else {
   120         has16bitFanCounter = true;
   121       }
   122 
   123       // Set the number of GPIO sets
   124       switch (chip) {
   125         case Chip.IT8712F:
   126         case Chip.IT8716F:
   127         case Chip.IT8718F:
   128         case Chip.IT8726F:
   129           gpioCount = 5;
   130           break;
   131         case Chip.IT8720F:
   132         case Chip.IT8721F:
   133           gpioCount = 8;
   134           break;
   135         case Chip.IT8728F:
   136         case Chip.IT8771E:
   137         case Chip.IT8772E:
   138           gpioCount = 0;
   139           break;
   140       }
   141     }
   142 
   143     public Chip Chip { get { return chip; } }
   144     public float?[] Voltages { get { return voltages; } }
   145     public float?[] Temperatures { get { return temperatures; } }
   146     public float?[] Fans { get { return fans; } }
   147     public float?[] Controls { get { return controls; } }
   148 
   149     public string GetReport() {
   150       StringBuilder r = new StringBuilder();
   151 
   152       r.AppendLine("LPC " + this.GetType().Name);
   153       r.AppendLine();
   154       r.Append("Chip ID: 0x"); r.AppendLine(chip.ToString("X"));
   155       r.Append("Chip Version: 0x"); r.AppendLine(
   156         version.ToString("X", CultureInfo.InvariantCulture));
   157       r.Append("Base Address: 0x"); r.AppendLine(
   158         address.ToString("X4", CultureInfo.InvariantCulture));
   159       r.Append("GPIO Address: 0x"); r.AppendLine(
   160         gpioAddress.ToString("X4", CultureInfo.InvariantCulture));
   161       r.AppendLine();
   162 
   163       if (!Ring0.WaitIsaBusMutex(100))
   164         return r.ToString();
   165 
   166       r.AppendLine("Environment Controller Registers");
   167       r.AppendLine();
   168       r.AppendLine("      00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
   169       r.AppendLine();
   170       for (int i = 0; i <= 0xA; i++) {
   171         r.Append(" "); 
   172         r.Append((i << 4).ToString("X2", CultureInfo.InvariantCulture)); 
   173         r.Append("  ");
   174         for (int j = 0; j <= 0xF; j++) {
   175           r.Append(" ");
   176           bool valid;
   177           byte value = ReadByte((byte)((i << 4) | j), out valid);
   178           r.Append(
   179             valid ? value.ToString("X2", CultureInfo.InvariantCulture) : "??");
   180         }
   181         r.AppendLine();
   182       }
   183       r.AppendLine();
   184 
   185       r.AppendLine("GPIO Registers");
   186       r.AppendLine();
   187       for (int i = 0; i < gpioCount; i++) {
   188         r.Append(" ");
   189         r.Append(ReadGPIO(i).Value.ToString("X2",
   190           CultureInfo.InvariantCulture));
   191       }
   192       r.AppendLine();
   193       r.AppendLine();
   194 
   195       Ring0.ReleaseIsaBusMutex();
   196 
   197       return r.ToString();
   198     }
   199 
   200     public void Update() {
   201       if (!Ring0.WaitIsaBusMutex(10))
   202         return;
   203 
   204       for (int i = 0; i < voltages.Length; i++) {
   205         bool valid;
   206         
   207         float value = 
   208           voltageGain * ReadByte((byte)(VOLTAGE_BASE_REG + i), out valid);   
   209 
   210         if (!valid)
   211           continue;
   212         if (value > 0)
   213           voltages[i] = value;  
   214         else
   215           voltages[i] = null;
   216       }
   217 
   218       for (int i = 0; i < temperatures.Length; i++) {
   219         bool valid;
   220         sbyte value = (sbyte)ReadByte(
   221           (byte)(TEMPERATURE_BASE_REG + i), out valid);
   222         if (!valid)
   223           continue;
   224 
   225         if (value < sbyte.MaxValue && value > 0)
   226           temperatures[i] = value;
   227         else
   228           temperatures[i] = null;       
   229       }
   230 
   231       if (has16bitFanCounter) {
   232         for (int i = 0; i < fans.Length; i++) {
   233           bool valid;
   234           int value = ReadByte(FAN_TACHOMETER_REG[i], out valid);
   235           if (!valid)
   236             continue;
   237           value |= ReadByte(FAN_TACHOMETER_EXT_REG[i], out valid) << 8;
   238           if (!valid)
   239             continue;
   240 
   241           if (value > 0x3f) {
   242             fans[i] = (value < 0xffff) ? 1.35e6f / (value * 2) : 0;
   243           } else {
   244             fans[i] = null;
   245           }
   246         }
   247       } else {
   248         for (int i = 0; i < fans.Length; i++) {
   249           bool valid;
   250           int value = ReadByte(FAN_TACHOMETER_REG[i], out valid);
   251           if (!valid)
   252             continue;
   253 
   254           int divisor = 2;
   255           if (i < 2) {
   256             int divisors = ReadByte(FAN_TACHOMETER_DIVISOR_REGISTER, out valid);
   257             if (!valid)
   258               continue;
   259             divisor = 1 << ((divisors >> (3 * i)) & 0x7);
   260           }
   261 
   262           if (value > 0) {
   263             fans[i] = (value < 0xff) ? 1.35e6f / (value * divisor) : 0;
   264           } else {
   265             fans[i] = null;
   266           }
   267         }
   268       }
   269 
   270       Ring0.ReleaseIsaBusMutex();
   271     }
   272   } 
   273 }