w83627hf.c revision ada0c2f8fa087dc1dbc34e096c318739b1d6381a
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf.c - Part of lm_sensors, Linux kernel modules for hardware 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds monitoring 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Copyright (c) 1998 - 2003 Frodo Looijaard <frodol@dds.nl>, 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Philip Edelbrock <phil@netroedge.com>, 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds and Mark Studebaker <mdsxyz123@yahoo.com> 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Ported to 2.6 by Bernhard C. Schrenk <clemy@clemy.org> 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This program is free software; you can redistribute it and/or modify 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds it under the terms of the GNU General Public License as published by 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds the Free Software Foundation; either version 2 of the License, or 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (at your option) any later version. 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This program is distributed in the hope that it will be useful, 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds but WITHOUT ANY WARRANTY; without even the implied warranty of 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds GNU General Public License for more details. 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds You should have received a copy of the GNU General Public License 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds along with this program; if not, write to the Free Software 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Supports following chips: 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Chip #vin #fanin #pwm #temp wchipid vendid i2c ISA 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf 9 3 2 3 0x20 0x5ca3 no yes(LPC) 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627thf 7 3 3 3 0x90 0x5ca3 no yes(LPC) 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83637hf 7 3 3 3 0x80 0x5ca3 no yes(LPC) 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83697hf 8 2 2 2 0x60 0x5ca3 no yes(LPC) 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds For other winbond chips, and for i2c support in the above chips, 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds use w83781d.c. 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Note: automatic ("cruise") fan control for 697, 637 & 627thf not 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds supported yet. 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/jiffies.h> 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/i2c.h> 45fde0950903ce8cc38a91dd095280decceda2ff82Jean Delvare#include <linux/i2c-isa.h> 46943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman#include <linux/hwmon.h> 47303760b44a7a142cb9f4c9df4609fb63bbda98dbJean Delvare#include <linux/hwmon-vid.h> 48943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman#include <linux/err.h> 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "lm75.h" 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u16 force_addr; 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(force_addr, ushort, 0); 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(force_addr, 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Initialize the base address of the sensors"); 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u8 force_i2c = 0x1f; 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(force_i2c, byte, 0); 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(force_i2c, 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Initialize the i2c address of the sensors"); 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 612d8672c5a6ba0d3f1d8d3ad61ef67868941364f0Jean Delvare/* The actual ISA address is read from Super-I/O configuration space */ 622d8672c5a6ba0d3f1d8d3ad61ef67868941364f0Jean Delvarestatic unsigned short address; 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Insmod parameters */ 652d8672c5a6ba0d3f1d8d3ad61ef67868941364f0Jean Delvareenum chips { any_chip, w83627hf, w83627thf, w83697hf, w83637hf }; 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 672251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvarestatic int reset; 682251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvaremodule_param(reset, bool, 0); 692251cf1a4b37bd483501614c2d78f5b8286f20d7Jean DelvareMODULE_PARM_DESC(reset, "Set to one to reset chip on load"); 702251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int init = 1; 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(init, bool, 0); 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(init, "Set to zero to bypass chip initialization"); 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* modified from kernel/include/traps.c */ 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int REG; /* The register to read/write */ 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DEV 0x07 /* Register: Logical device select */ 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int VAL; /* The value to read/write */ 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* logical device numbers for superio_select (below) */ 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_FDC 0x00 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_PRT 0x01 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_UART1 0x02 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_UART2 0x03 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_KBC 0x05 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_CIR 0x06 /* w83627hf only */ 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_GAME 0x07 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_MIDI 0x07 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_GPIO1 0x07 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_GPIO5 0x07 /* w83627thf only */ 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_GPIO2 0x08 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_GPIO3 0x09 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_GPIO4 0x09 /* w83627thf only */ 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_ACPI 0x0a 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_LD_HWM 0x0b 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DEVID 0x20 /* Register: Device ID */ 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627THF_GPIO5_EN 0x30 /* w83627thf only */ 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627THF_GPIO5_IOSR 0xf3 /* w83627thf only */ 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627THF_GPIO5_DR 0xf4 /* w83627thf only */ 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssuperio_outb(int reg, int val) 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(reg, REG); 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(val, VAL); 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssuperio_inb(int reg) 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(reg, REG); 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return inb(VAL); 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssuperio_select(int ld) 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(DEV, REG); 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(ld, VAL); 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssuperio_enter(void) 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x87, REG); 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x87, REG); 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssuperio_exit(void) 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0xAA, REG); 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W627_DEVID 0x52 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W627THF_DEVID 0x82 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W697_DEVID 0x60 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W637_DEVID 0x70 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define WINB_ACT_REG 0x30 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define WINB_BASE_REG 0x60 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Constants specified below */ 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 145ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec/* Alignment of the base address */ 146ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec#define WINB_ALIGNMENT ~7 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 148ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec/* Offset & size of I/O region we are interested in */ 149ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec#define WINB_REGION_OFFSET 5 150ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec#define WINB_REGION_SIZE 2 151ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec 152ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec/* Where are the sensors address/data registers relative to the base address */ 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_ADDR_REG_OFFSET 5 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_DATA_REG_OFFSET 6 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The W83781D registers */ 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The W83782D registers for nr=7,8 are in bank 5 */ 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_IN_MAX(nr) ((nr < 7) ? (0x2b + (nr) * 2) : \ 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (0x554 + (((nr) - 7) * 2))) 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_IN_MIN(nr) ((nr < 7) ? (0x2c + (nr) * 2) : \ 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (0x555 + (((nr) - 7) * 2))) 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_IN(nr) ((nr < 7) ? (0x20 + (nr)) : \ 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (0x550 + (nr) - 7)) 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_FAN_MIN(nr) (0x3a + (nr)) 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_FAN(nr) (0x27 + (nr)) 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_TEMP2_CONFIG 0x152 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_TEMP3_CONFIG 0x252 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_TEMP(nr) ((nr == 3) ? (0x0250) : \ 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((nr == 2) ? (0x0150) : \ 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (0x27))) 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_TEMP_HYST(nr) ((nr == 3) ? (0x253) : \ 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((nr == 2) ? (0x153) : \ 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (0x3A))) 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_TEMP_OVER(nr) ((nr == 3) ? (0x255) : \ 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((nr == 2) ? (0x155) : \ 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (0x39))) 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_BANK 0x4E 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_CONFIG 0x40 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_ALARM1 0x41 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_ALARM2 0x42 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_ALARM3 0x450 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_IRQ 0x4C 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_BEEP_CONFIG 0x4D 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_BEEP_INTS1 0x56 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_BEEP_INTS2 0x57 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_BEEP_INTS3 0x453 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_VID_FANDIV 0x47 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_CHIPID 0x49 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_WCHIPID 0x58 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_CHIPMAN 0x4F 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_PIN 0x4B 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_VBAT 0x5D 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_REG_PWM1 0x5A 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_REG_PWM2 0x5B 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627HF_REG_PWMCLK12 0x5C 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627THF_REG_PWM1 0x01 /* 697HF and 637HF too */ 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627THF_REG_PWM2 0x03 /* 697HF and 637HF too */ 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627THF_REG_PWM3 0x11 /* 637HF too */ 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83627THF_REG_VRM_OVT_CFG 0x18 /* 637HF too */ 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const u8 regpwm_627hf[] = { W83627HF_REG_PWM1, W83627HF_REG_PWM2 }; 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const u8 regpwm[] = { W83627THF_REG_PWM1, W83627THF_REG_PWM2, 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds W83627THF_REG_PWM3 }; 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W836X7HF_REG_PWM(type, nr) (((type) == w83627hf) ? \ 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds regpwm_627hf[(nr) - 1] : regpwm[(nr) - 1]) 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_I2C_ADDR 0x48 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_I2C_SUBADDR 0x4A 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Sensor selection */ 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_SCFG1 0x5D 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const u8 BIT_SCFG1[] = { 0x02, 0x04, 0x08 }; 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_REG_SCFG2 0x59 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const u8 BIT_SCFG2[] = { 0x10, 0x20, 0x40 }; 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define W83781D_DEFAULT_BETA 3435 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Conversions. Limit checking is only done on the TO_REG 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds variants. Note that you should be a bit careful with which arguments 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds these macros are called: arguments may be evaluated more than once. 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Fixing this is just not worth it. */ 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IN_TO_REG(val) (SENSORS_LIMIT((((val) + 8)/16),0,255)) 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IN_FROM_REG(val) ((val) * 16) 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u8 FAN_TO_REG(long rpm, int div) 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rpm == 0) 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 255; 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rpm = SENSORS_LIMIT(rpm, 1, 1000000); 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 254); 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEMP_MIN (-128000) 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEMP_MAX ( 127000) 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* TEMP: 0.001C/bit (-128C to +127C) 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REG: 1C/bit, two's complement */ 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u8 TEMP_TO_REG(int temp) 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ntemp = SENSORS_LIMIT(temp, TEMP_MIN, TEMP_MAX); 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ntemp += (ntemp<0 ? -500 : 500); 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (u8)(ntemp / 1000); 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int TEMP_FROM_REG(u8 reg) 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (s8)reg * 1000; 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FAN_FROM_REG(val,div) ((val)==0?-1:(val)==255?0:1350000/((val)*(div))) 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PWM_TO_REG(val) (SENSORS_LIMIT((val),0,255)) 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BEEP_MASK_FROM_REG(val) (val) 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BEEP_MASK_TO_REG(val) ((val) & 0xffffff) 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BEEP_ENABLE_TO_REG(val) ((val)?1:0) 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BEEP_ENABLE_FROM_REG(val) ((val)?1:0) 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DIV_FROM_REG(val) (1 << (val)) 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u8 DIV_TO_REG(long val) 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = SENSORS_LIMIT(val, 1, 128) >> 1; 276abc01922477104e8d72b494902aff37135c409e7Grant Coady for (i = 0; i < 7; i++) { 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (val == 0) 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val >>= 1; 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ((u8) i); 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* For each registered chip, we need to keep some data in memory. That 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data is pointed to by w83627hf_list[NR]->data. The structure itself is 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dynamically allocated, at the same time when a new client is allocated. */ 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct w83627hf_data { 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2c_client client; 289943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman struct class_device *class_dev; 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct semaphore lock; 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enum chips type; 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct semaphore update_lock; 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char valid; /* !=0 if following fields are valid */ 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long last_updated; /* In jiffies */ 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2c_client *lm75; /* for secondary I2C addresses */ 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* pointer to array of 2 subclients */ 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 in[9]; /* Register value */ 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 in_max[9]; /* Register value */ 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 in_min[9]; /* Register value */ 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 fan[3]; /* Register value */ 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 fan_min[3]; /* Register value */ 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 temp; 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 temp_max; /* Register value */ 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 temp_max_hyst; /* Register value */ 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 temp_add[2]; /* Register value */ 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 temp_max_add[2]; /* Register value */ 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 temp_max_hyst_add[2]; /* Register value */ 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 fan_div[3]; /* Register encoding, shifted right */ 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 vid; /* Register encoding, combined */ 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 alarms; /* Register encoding, combined */ 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 beep_mask; /* Register encoding, combined */ 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 beep_enable; /* Boolean */ 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 pwm[3]; /* Register value */ 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 sens[3]; /* 782D/783S only. 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1 = pentium diode; 2 = 3904 diode; 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3000-5000 = thermistor beta. 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Default = 3435. 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Other Betas unimplemented */ 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 vrm; 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 vrm_ovt; /* Register value, 627thf & 637hf only */ 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3272d8672c5a6ba0d3f1d8d3ad61ef67868941364f0Jean Delvarestatic int w83627hf_detect(struct i2c_adapter *adapter); 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int w83627hf_detach_client(struct i2c_client *client); 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int w83627hf_read_value(struct i2c_client *client, u16 register); 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int w83627hf_write_value(struct i2c_client *client, u16 register, 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 value); 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct w83627hf_data *w83627hf_update_device(struct device *dev); 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void w83627hf_init_client(struct i2c_client *client); 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct i2c_driver w83627hf_driver = { 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .owner = THIS_MODULE, 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .name = "w83627hf", 3392d8672c5a6ba0d3f1d8d3ad61ef67868941364f0Jean Delvare .attach_adapter = w83627hf_detect, 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .detach_client = w83627hf_detach_client, 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* following are the sysfs callback functions */ 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define show_in_reg(reg) \ 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t show_##reg (struct device *dev, char *buf, int nr) \ 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \ 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct w83627hf_data *data = w83627hf_update_device(dev); \ 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf(buf,"%ld\n", (long)IN_FROM_REG(data->reg[nr])); \ 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_in_reg(in) 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_in_reg(in_min) 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_in_reg(in_max) 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define store_in_reg(REG, reg) \ 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t \ 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstore_in_##reg (struct device *dev, const char *buf, size_t count, int nr) \ 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \ 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2c_client *client = to_i2c_client(dev); \ 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct w83627hf_data *data = i2c_get_clientdata(client); \ 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 val; \ 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds \ 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = simple_strtoul(buf, NULL, 10); \ 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds \ 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds down(&data->update_lock); \ 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->in_##reg[nr] = IN_TO_REG(val); \ 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_write_value(client, W83781D_REG_IN_##REG(nr), \ 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->in_##reg[nr]); \ 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds \ 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up(&data->update_lock); \ 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return count; \ 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstore_in_reg(MIN, min) 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstore_in_reg(MAX, max) 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_in_offset(offset) \ 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t \ 377a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoushow_regs_in_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \ 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return show_in(dev, buf, offset); \ 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \ 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(in##offset##_input, S_IRUGO, show_regs_in_##offset, NULL); 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_in_reg_offset(reg, offset) \ 384a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \ 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \ 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return show_in_##reg (dev, buf, offset); \ 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \ 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t \ 389a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustore_regs_in_##reg##offset (struct device *dev, struct device_attribute *attr, \ 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const char *buf, size_t count) \ 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \ 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return store_in_##reg (dev, buf, count, offset); \ 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \ 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(in##offset##_##reg, S_IRUGO| S_IWUSR, \ 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds show_regs_in_##reg##offset, store_regs_in_##reg##offset); 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_in_offsets(offset) \ 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in_offset(offset) \ 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in_reg_offset(min, offset) \ 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in_reg_offset(max, offset) 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in_offsets(1); 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in_offsets(2); 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in_offsets(3); 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in_offsets(4); 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in_offsets(5); 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in_offsets(6); 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in_offsets(7); 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_in_offsets(8); 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* use a different set of functions for in0 */ 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t show_in_0(struct w83627hf_data *data, char *buf, u8 reg) 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds long in0; 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((data->vrm_ovt & 0x01) && 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (w83627thf == data->type || w83637hf == data->type)) 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* use VRM9 calculation */ 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds in0 = (long)((reg * 488 + 70000 + 50) / 100); 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* use VRM8 (standard) calculation */ 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds in0 = (long)IN_FROM_REG(reg); 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf(buf,"%ld\n", in0); 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 428a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_in_0(struct device *dev, struct device_attribute *attr, char *buf) 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct w83627hf_data *data = w83627hf_update_device(dev); 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return show_in_0(data, buf, data->in[0]); 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 434a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_in_min0(struct device *dev, struct device_attribute *attr, char *buf) 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct w83627hf_data *data = w83627hf_update_device(dev); 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return show_in_0(data, buf, data->in_min[0]); 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 440a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_in_max0(struct device *dev, struct device_attribute *attr, char *buf) 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct w83627hf_data *data = w83627hf_update_device(dev); 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return show_in_0(data, buf, data->in_max[0]); 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 446a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t store_regs_in_min0(struct device *dev, struct device_attribute *attr, 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const char *buf, size_t count) 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2c_client *client = to_i2c_client(dev); 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct w83627hf_data *data = i2c_get_clientdata(client); 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 val; 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = simple_strtoul(buf, NULL, 10); 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds down(&data->update_lock); 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((data->vrm_ovt & 0x01) && 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (w83627thf == data->type || w83637hf == data->type)) 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* use VRM9 calculation */ 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->in_min[0] = (u8)(((val * 100) - 70000 + 244) / 488); 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* use VRM8 (standard) calculation */ 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->in_min[0] = IN_TO_REG(val); 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_write_value(client, W83781D_REG_IN_MIN(0), data->in_min[0]); 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up(&data->update_lock); 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return count; 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 471a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t store_regs_in_max0(struct device *dev, struct device_attribute *attr, 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const char *buf, size_t count) 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2c_client *client = to_i2c_client(dev); 4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct w83627hf_data *data = i2c_get_clientdata(client); 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 val; 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = simple_strtoul(buf, NULL, 10); 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds down(&data->update_lock); 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((data->vrm_ovt & 0x01) && 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (w83627thf == data->type || w83637hf == data->type)) 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* use VRM9 calculation */ 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->in_max[0] = (u8)(((val * 100) - 70000 + 244) / 488); 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* use VRM8 (standard) calculation */ 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->in_max[0] = IN_TO_REG(val); 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_write_value(client, W83781D_REG_IN_MAX(0), data->in_max[0]); 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up(&data->update_lock); 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return count; 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(in0_input, S_IRUGO, show_regs_in_0, NULL); 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(in0_min, S_IRUGO | S_IWUSR, 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds show_regs_in_min0, store_regs_in_min0); 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(in0_max, S_IRUGO | S_IWUSR, 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds show_regs_in_max0, store_regs_in_max0); 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define device_create_file_in(client, offset) \ 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo { \ 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_create_file(&client->dev, &dev_attr_in##offset##_input); \ 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_create_file(&client->dev, &dev_attr_in##offset##_min); \ 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_create_file(&client->dev, &dev_attr_in##offset##_max); \ 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} while (0) 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define show_fan_reg(reg) \ 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t show_##reg (struct device *dev, char *buf, int nr) \ 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \ 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct w83627hf_data *data = w83627hf_update_device(dev); \ 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf(buf,"%ld\n", \ 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FAN_FROM_REG(data->reg[nr-1], \ 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (long)DIV_FROM_REG(data->fan_div[nr-1]))); \ 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_fan_reg(fan); 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_fan_reg(fan_min); 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstore_fan_min(struct device *dev, const char *buf, size_t count, int nr) 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2c_client *client = to_i2c_client(dev); 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct w83627hf_data *data = i2c_get_clientdata(client); 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 val; 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = simple_strtoul(buf, NULL, 10); 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds down(&data->update_lock); 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fan_min[nr - 1] = 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr - 1])); 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_write_value(client, W83781D_REG_FAN_MIN(nr), 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fan_min[nr - 1]); 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up(&data->update_lock); 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return count; 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_fan_offset(offset) \ 540a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_fan_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \ 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return show_fan(dev, buf, offset); \ 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \ 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_regs_fan_##offset, NULL); 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_fan_min_offset(offset) \ 547a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, char *buf) \ 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \ 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return show_fan_min(dev, buf, offset); \ 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \ 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t \ 552a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustore_regs_fan_min##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \ 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return store_fan_min(dev, buf, count, offset); \ 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \ 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds show_regs_fan_min##offset, store_regs_fan_min##offset); 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_fan_offset(1); 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_fan_min_offset(1); 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_fan_offset(2); 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_fan_min_offset(2); 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_fan_offset(3); 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_fan_min_offset(3); 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define device_create_file_fan(client, offset) \ 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo { \ 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_create_file(&client->dev, &dev_attr_fan##offset##_input); \ 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_create_file(&client->dev, &dev_attr_fan##offset##_min); \ 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} while (0) 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define show_temp_reg(reg) \ 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t show_##reg (struct device *dev, char *buf, int nr) \ 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \ 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct w83627hf_data *data = w83627hf_update_device(dev); \ 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (nr >= 2) { /* TEMP2 and TEMP3 */ \ 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf(buf,"%ld\n", \ 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (long)LM75_TEMP_FROM_REG(data->reg##_add[nr-2])); \ 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { /* TEMP1 */ \ 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf(buf,"%ld\n", (long)TEMP_FROM_REG(data->reg)); \ 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } \ 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_temp_reg(temp); 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_temp_reg(temp_max); 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_temp_reg(temp_max_hyst); 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define store_temp_reg(REG, reg) \ 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t \ 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstore_temp_##reg (struct device *dev, const char *buf, size_t count, int nr) \ 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \ 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2c_client *client = to_i2c_client(dev); \ 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct w83627hf_data *data = i2c_get_clientdata(client); \ 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 val; \ 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds \ 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = simple_strtoul(buf, NULL, 10); \ 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds \ 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds down(&data->update_lock); \ 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds \ 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (nr >= 2) { /* TEMP2 and TEMP3 */ \ 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->temp_##reg##_add[nr-2] = LM75_TEMP_TO_REG(val); \ 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_write_value(client, W83781D_REG_TEMP_##REG(nr), \ 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->temp_##reg##_add[nr-2]); \ 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { /* TEMP1 */ \ 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->temp_##reg = TEMP_TO_REG(val); \ 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_write_value(client, W83781D_REG_TEMP_##REG(nr), \ 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->temp_##reg); \ 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } \ 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds \ 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up(&data->update_lock); \ 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return count; \ 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstore_temp_reg(OVER, max); 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstore_temp_reg(HYST, max_hyst); 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_temp_offset(offset) \ 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t \ 617a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoushow_regs_temp_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \ 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return show_temp(dev, buf, offset); \ 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \ 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(temp##offset##_input, S_IRUGO, show_regs_temp_##offset, NULL); 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_temp_reg_offset(reg, offset) \ 624a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, char *buf) \ 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \ 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return show_temp_##reg (dev, buf, offset); \ 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \ 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t \ 629a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustore_regs_temp_##reg##offset (struct device *dev, struct device_attribute *attr, \ 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const char *buf, size_t count) \ 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \ 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return store_temp_##reg (dev, buf, count, offset); \ 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \ 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(temp##offset##_##reg, S_IRUGO| S_IWUSR, \ 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds show_regs_temp_##reg##offset, store_regs_temp_##reg##offset); 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_temp_offsets(offset) \ 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_temp_offset(offset) \ 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_temp_reg_offset(max, offset) \ 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_temp_reg_offset(max_hyst, offset) 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_temp_offsets(1); 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_temp_offsets(2); 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_temp_offsets(3); 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define device_create_file_temp(client, offset) \ 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo { \ 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_create_file(&client->dev, &dev_attr_temp##offset##_input); \ 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_create_file(&client->dev, &dev_attr_temp##offset##_max); \ 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_create_file(&client->dev, &dev_attr_temp##offset##_max_hyst); \ 6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} while (0) 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t 654a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoushow_vid_reg(struct device *dev, struct device_attribute *attr, char *buf) 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct w83627hf_data *data = w83627hf_update_device(dev); 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf(buf, "%ld\n", (long) vid_from_reg(data->vid, data->vrm)); 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid_reg, NULL); 6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define device_create_file_vid(client) \ 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_create_file(&client->dev, &dev_attr_cpu0_vid) 6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t 664a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoushow_vrm_reg(struct device *dev, struct device_attribute *attr, char *buf) 6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct w83627hf_data *data = w83627hf_update_device(dev); 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf(buf, "%ld\n", (long) data->vrm); 6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t 670a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustore_vrm_reg(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2c_client *client = to_i2c_client(dev); 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct w83627hf_data *data = i2c_get_clientdata(client); 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 val; 6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = simple_strtoul(buf, NULL, 10); 6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->vrm = val; 6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return count; 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm_reg, store_vrm_reg); 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define device_create_file_vrm(client) \ 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_create_file(&client->dev, &dev_attr_vrm) 6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t 686a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoushow_alarms_reg(struct device *dev, struct device_attribute *attr, char *buf) 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct w83627hf_data *data = w83627hf_update_device(dev); 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf(buf, "%ld\n", (long) data->alarms); 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(alarms, S_IRUGO, show_alarms_reg, NULL); 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define device_create_file_alarms(client) \ 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_create_file(&client->dev, &dev_attr_alarms) 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define show_beep_reg(REG, reg) \ 696a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \ 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \ 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct w83627hf_data *data = w83627hf_update_device(dev); \ 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf(buf,"%ld\n", \ 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (long)BEEP_##REG##_FROM_REG(data->beep_##reg)); \ 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_beep_reg(ENABLE, enable) 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_beep_reg(MASK, mask) 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BEEP_ENABLE 0 /* Store beep_enable */ 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BEEP_MASK 1 /* Store beep_mask */ 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstore_beep_reg(struct device *dev, const char *buf, size_t count, 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int update_mask) 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2c_client *client = to_i2c_client(dev); 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct w83627hf_data *data = i2c_get_clientdata(client); 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 val, val2; 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = simple_strtoul(buf, NULL, 10); 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds down(&data->update_lock); 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (update_mask == BEEP_MASK) { /* We are storing beep_mask */ 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->beep_mask = BEEP_MASK_TO_REG(val); 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_write_value(client, W83781D_REG_BEEP_INTS1, 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->beep_mask & 0xff); 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_write_value(client, W83781D_REG_BEEP_INTS3, 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((data->beep_mask) >> 16) & 0xff); 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val2 = (data->beep_mask >> 8) & 0x7f; 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { /* We are storing beep_enable */ 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val2 = 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_read_value(client, W83781D_REG_BEEP_INTS2) & 0x7f; 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->beep_enable = BEEP_ENABLE_TO_REG(val); 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_write_value(client, W83781D_REG_BEEP_INTS2, 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val2 | data->beep_enable << 7); 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up(&data->update_lock); 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return count; 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_beep(REG, reg) \ 741a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_beep_##reg (struct device *dev, struct device_attribute *attr, char *buf) \ 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \ 743a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannou return show_beep_##reg(dev, attr, buf); \ 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \ 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t \ 746a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustore_regs_beep_##reg (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \ 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return store_beep_reg(dev, buf, count, BEEP_##REG); \ 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \ 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(beep_##reg, S_IRUGO | S_IWUSR, \ 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds show_regs_beep_##reg, store_regs_beep_##reg); 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_beep(ENABLE, enable); 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_beep(MASK, mask); 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define device_create_file_beep(client) \ 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo { \ 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_create_file(&client->dev, &dev_attr_beep_enable); \ 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_create_file(&client->dev, &dev_attr_beep_mask); \ 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} while (0) 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_fan_div_reg(struct device *dev, char *buf, int nr) 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct w83627hf_data *data = w83627hf_update_device(dev); 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf(buf, "%ld\n", 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (long) DIV_FROM_REG(data->fan_div[nr - 1])); 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Note: we save and restore the fan minimum here, because its value is 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds determined in part by the fan divisor. This follows the principle of 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds least suprise; the user doesn't expect the fan minimum to change just 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds because the divisor changed. */ 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstore_fan_div_reg(struct device *dev, const char *buf, size_t count, int nr) 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2c_client *client = to_i2c_client(dev); 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct w83627hf_data *data = i2c_get_clientdata(client); 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long min; 7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 reg; 7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long val = simple_strtoul(buf, NULL, 10); 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds down(&data->update_lock); 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Save fan_min */ 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds min = FAN_FROM_REG(data->fan_min[nr], 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DIV_FROM_REG(data->fan_div[nr])); 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fan_div[nr] = DIV_TO_REG(val); 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg = (w83627hf_read_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV) 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds & (nr==0 ? 0xcf : 0x3f)) 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ((data->fan_div[nr] & 0x03) << (nr==0 ? 4 : 6)); 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_write_value(client, nr==2 ? W83781D_REG_PIN : W83781D_REG_VID_FANDIV, reg); 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg = (w83627hf_read_value(client, W83781D_REG_VBAT) 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds & ~(1 << (5 + nr))) 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ((data->fan_div[nr] & 0x04) << (3 + nr)); 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_write_value(client, W83781D_REG_VBAT, reg); 8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Restore fan_min */ 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fan_min[nr] = FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_write_value(client, W83781D_REG_FAN_MIN(nr+1), data->fan_min[nr]); 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up(&data->update_lock); 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return count; 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_fan_div(offset) \ 810a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \ 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return show_fan_div_reg(dev, buf, offset); \ 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \ 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t \ 815a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustore_regs_fan_div_##offset (struct device *dev, struct device_attribute *attr, \ 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const char *buf, size_t count) \ 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \ 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return store_fan_div_reg(dev, buf, count, offset - 1); \ 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \ 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR, \ 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds show_regs_fan_div_##offset, store_regs_fan_div_##offset); 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_fan_div(1); 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_fan_div(2); 8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_fan_div(3); 8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define device_create_file_fan_div(client, offset) \ 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo { \ 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_create_file(&client->dev, &dev_attr_fan##offset##_div); \ 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} while (0) 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_pwm_reg(struct device *dev, char *buf, int nr) 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct w83627hf_data *data = w83627hf_update_device(dev); 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf(buf, "%ld\n", (long) data->pwm[nr - 1]); 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstore_pwm_reg(struct device *dev, const char *buf, size_t count, int nr) 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2c_client *client = to_i2c_client(dev); 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct w83627hf_data *data = i2c_get_clientdata(client); 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 val; 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = simple_strtoul(buf, NULL, 10); 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds down(&data->update_lock); 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->type == w83627thf) { 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* bits 0-3 are reserved in 627THF */ 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->pwm[nr - 1] = PWM_TO_REG(val) & 0xf0; 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_write_value(client, 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds W836X7HF_REG_PWM(data->type, nr), 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->pwm[nr - 1] | 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (w83627hf_read_value(client, 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds W836X7HF_REG_PWM(data->type, nr)) & 0x0f)); 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->pwm[nr - 1] = PWM_TO_REG(val); 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_write_value(client, 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds W836X7HF_REG_PWM(data->type, nr), 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->pwm[nr - 1]); 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up(&data->update_lock); 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return count; 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_pwm(offset) \ 870a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \ 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return show_pwm_reg(dev, buf, offset); \ 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \ 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t \ 875a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustore_regs_pwm_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \ 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return store_pwm_reg(dev, buf, count, offset); \ 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \ 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR, \ 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds show_regs_pwm_##offset, store_regs_pwm_##offset); 8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_pwm(1); 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_pwm(2); 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_pwm(3); 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define device_create_file_pwm(client, offset) \ 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo { \ 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_create_file(&client->dev, &dev_attr_pwm##offset); \ 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} while (0) 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_sensor_reg(struct device *dev, char *buf, int nr) 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct w83627hf_data *data = w83627hf_update_device(dev); 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf(buf, "%ld\n", (long) data->sens[nr - 1]); 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstore_sensor_reg(struct device *dev, const char *buf, size_t count, int nr) 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2c_client *client = to_i2c_client(dev); 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct w83627hf_data *data = i2c_get_clientdata(client); 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 val, tmp; 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = simple_strtoul(buf, NULL, 10); 9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds down(&data->update_lock); 9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (val) { 9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 1: /* PII/Celeron diode */ 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = w83627hf_read_value(client, W83781D_REG_SCFG1); 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_write_value(client, W83781D_REG_SCFG1, 9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp | BIT_SCFG1[nr - 1]); 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = w83627hf_read_value(client, W83781D_REG_SCFG2); 9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_write_value(client, W83781D_REG_SCFG2, 9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp | BIT_SCFG2[nr - 1]); 9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->sens[nr - 1] = val; 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 2: /* 3904 */ 9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = w83627hf_read_value(client, W83781D_REG_SCFG1); 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_write_value(client, W83781D_REG_SCFG1, 9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp | BIT_SCFG1[nr - 1]); 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = w83627hf_read_value(client, W83781D_REG_SCFG2); 9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_write_value(client, W83781D_REG_SCFG2, 9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp & ~BIT_SCFG2[nr - 1]); 9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->sens[nr - 1] = val; 9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case W83781D_DEFAULT_BETA: /* thermistor */ 9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = w83627hf_read_value(client, W83781D_REG_SCFG1); 9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_write_value(client, W83781D_REG_SCFG1, 9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp & ~BIT_SCFG1[nr - 1]); 9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->sens[nr - 1] = val; 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_err(&client->dev, 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Invalid sensor type %ld; must be 1, 2, or %d\n", 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (long) val, W83781D_DEFAULT_BETA); 9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up(&data->update_lock); 9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return count; 9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define sysfs_sensor(offset) \ 946a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustatic ssize_t show_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, char *buf) \ 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \ 9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return show_sensor_reg(dev, buf, offset); \ 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \ 9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic ssize_t \ 951a5099cfc2e82240b0a3e72ad79a5969d5af1a7dcYani Ioannoustore_regs_sensor_##offset (struct device *dev, struct device_attribute *attr, const char *buf, size_t count) \ 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ \ 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return store_sensor_reg(dev, buf, count, offset); \ 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} \ 9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(temp##offset##_type, S_IRUGO | S_IWUSR, \ 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds show_regs_sensor_##offset, store_regs_sensor_##offset); 9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_sensor(1); 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_sensor(2); 9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssysfs_sensor(3); 9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define device_create_file_sensor(client, offset) \ 9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo { \ 9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdevice_create_file(&client->dev, &dev_attr_temp##offset##_type); \ 9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} while (0) 9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 968e6cfb3ad7209e4f4dcdc14f5fc437db55667041fJean Delvarestatic int __init w83627hf_find(int sioaddr, unsigned short *addr) 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 val; 9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds REG = sioaddr; 9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds VAL = sioaddr + 1; 9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds superio_enter(); 9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val= superio_inb(DEVID); 9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(val != W627_DEVID && 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val != W627THF_DEVID && 9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val != W697_DEVID && 9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val != W637_DEVID) { 9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds superio_exit(); 9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds superio_select(W83627HF_LD_HWM); 9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = (superio_inb(WINB_BASE_REG) << 8) | 9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds superio_inb(WINB_BASE_REG + 1); 988ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec *addr = val & WINB_ALIGNMENT; 9892d8672c5a6ba0d3f1d8d3ad61ef67868941364f0Jean Delvare if (*addr == 0 && force_addr == 0) { 9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds superio_exit(); 9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds superio_exit(); 9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9982d8672c5a6ba0d3f1d8d3ad61ef67868941364f0Jean Delvarestatic int w83627hf_detect(struct i2c_adapter *adapter) 9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10002d8672c5a6ba0d3f1d8d3ad61ef67868941364f0Jean Delvare int val, kind; 10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2c_client *new_client; 10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct w83627hf_data *data; 10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err = 0; 10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const char *client_name = ""; 10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(force_addr) 1007ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec address = force_addr & WINB_ALIGNMENT; 10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1009ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec if (!request_region(address + WINB_REGION_OFFSET, WINB_REGION_SIZE, 1010ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec w83627hf_driver.name)) { 10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EBUSY; 10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto ERROR0; 10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(force_addr) { 10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("w83627hf.o: forcing ISA address 0x%04X\n", address); 10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds superio_enter(); 10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds superio_select(W83627HF_LD_HWM); 10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds superio_outb(WINB_BASE_REG, address >> 8); 10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds superio_outb(WINB_BASE_REG+1, address & 0xff); 10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds superio_exit(); 10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds superio_enter(); 10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val= superio_inb(DEVID); 10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(val == W627_DEVID) 10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kind = w83627hf; 10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if(val == W697_DEVID) 10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kind = w83697hf; 10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if(val == W627THF_DEVID) 10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kind = w83627thf; 10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if(val == W637_DEVID) 10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kind = w83637hf; 10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_info(&adapter->dev, 10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Unsupported chip (dev_id=0x%02X).\n", val); 10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto ERROR1; 10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds superio_select(W83627HF_LD_HWM); 10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if((val = 0x01 & superio_inb(WINB_ACT_REG)) == 0) 10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds superio_outb(WINB_ACT_REG, 1); 10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds superio_exit(); 10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* OK. For now, we presume we have a valid client. We now create the 10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds client structure, even though we cannot fill it completely yet. 10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds But it allows us to access w83627hf_{read,write}_value. */ 10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(data = kmalloc(sizeof(struct w83627hf_data), GFP_KERNEL))) { 10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -ENOMEM; 10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto ERROR1; 10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(data, 0, sizeof(struct w83627hf_data)); 10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_client = &data->client; 10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i2c_set_clientdata(new_client, data); 10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_client->addr = address; 10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_MUTEX(&data->lock); 10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_client->adapter = adapter; 10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_client->driver = &w83627hf_driver; 10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds new_client->flags = 0; 10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kind == w83627hf) { 10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds client_name = "w83627hf"; 10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (kind == w83627thf) { 10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds client_name = "w83627thf"; 10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (kind == w83697hf) { 10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds client_name = "w83697hf"; 10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (kind == w83637hf) { 10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds client_name = "w83637hf"; 10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Fill in the remaining client fields and put into the global list */ 10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds strlcpy(new_client->name, client_name, I2C_NAME_SIZE); 10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->type = kind; 10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->valid = 0; 10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds init_MUTEX(&data->update_lock); 10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Tell the I2C layer a new client has arrived */ 10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((err = i2c_attach_client(new_client))) 10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto ERROR2; 10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->lm75 = NULL; 10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Initialize the chip */ 10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_init_client(new_client); 10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* A few vars need to be filled upon startup */ 10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fan_min[0] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(1)); 10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fan_min[1] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(2)); 10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fan_min[2] = w83627hf_read_value(new_client, W83781D_REG_FAN_MIN(3)); 10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Register sysfs hooks */ 1095943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman data->class_dev = hwmon_device_register(&new_client->dev); 1096943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman if (IS_ERR(data->class_dev)) { 1097943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman err = PTR_ERR(data->class_dev); 1098943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman goto ERROR3; 1099943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman } 1100943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman 11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_create_file_in(new_client, 0); 11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kind != w83697hf) 11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_create_file_in(new_client, 1); 11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_create_file_in(new_client, 2); 11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_create_file_in(new_client, 3); 11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_create_file_in(new_client, 4); 11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kind != w83627thf && kind != w83637hf) { 11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_create_file_in(new_client, 5); 11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_create_file_in(new_client, 6); 11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_create_file_in(new_client, 7); 11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_create_file_in(new_client, 8); 11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_create_file_fan(new_client, 1); 11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_create_file_fan(new_client, 2); 11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kind != w83697hf) 11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_create_file_fan(new_client, 3); 11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_create_file_temp(new_client, 1); 11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_create_file_temp(new_client, 2); 11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kind != w83697hf) 11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_create_file_temp(new_client, 3); 11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kind != w83697hf) 11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_create_file_vid(new_client); 11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kind != w83697hf) 11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_create_file_vrm(new_client); 11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_create_file_fan_div(new_client, 1); 11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_create_file_fan_div(new_client, 2); 11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kind != w83697hf) 11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_create_file_fan_div(new_client, 3); 11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_create_file_alarms(new_client); 11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_create_file_beep(new_client); 11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_create_file_pwm(new_client, 1); 11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_create_file_pwm(new_client, 2); 11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kind == w83627thf || kind == w83637hf) 11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_create_file_pwm(new_client, 3); 11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_create_file_sensor(new_client, 1); 11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_create_file_sensor(new_client, 2); 11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kind != w83697hf) 11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds device_create_file_sensor(new_client, 3); 11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1151943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman ERROR3: 1152943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman i2c_detach_client(new_client); 11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ERROR2: 11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(data); 11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ERROR1: 1156ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec release_region(address + WINB_REGION_OFFSET, WINB_REGION_SIZE); 11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ERROR0: 11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int w83627hf_detach_client(struct i2c_client *client) 11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1163943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman struct w83627hf_data *data = i2c_get_clientdata(client); 11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1166943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman hwmon_device_unregister(data->class_dev); 1167943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman 11687bef559455fc71f66f8573cc1aafe1dd33966c1cJean Delvare if ((err = i2c_detach_client(client))) 11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1171ada0c2f8fa087dc1dbc34e096c318739b1d6381aPetr Vandrovec release_region(client->addr + WINB_REGION_OFFSET, WINB_REGION_SIZE); 1172943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman kfree(data); 11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ISA access must always be locked explicitly! 11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds We ignore the W83781D BUSY flag at this moment - it could lead to deadlocks, 11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds would slow down the W83781D access and should not be necessary. 11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds There are some ugly typecasts here, but the good news is - they should 11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nowhere else be necessary! */ 11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int w83627hf_read_value(struct i2c_client *client, u16 reg) 11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct w83627hf_data *data = i2c_get_clientdata(client); 11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int res, word_sized; 11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds down(&data->lock); 11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds word_sized = (((reg & 0xff00) == 0x100) 11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || ((reg & 0xff00) == 0x200)) 11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (((reg & 0x00ff) == 0x50) 11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || ((reg & 0x00ff) == 0x53) 11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || ((reg & 0x00ff) == 0x55)); 11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (reg & 0xff00) { 11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(W83781D_REG_BANK, 11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds client->addr + W83781D_ADDR_REG_OFFSET); 11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(reg >> 8, 11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds client->addr + W83781D_DATA_REG_OFFSET); 12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET); 12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = inb_p(client->addr + W83781D_DATA_REG_OFFSET); 12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (word_sized) { 12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p((reg & 0xff) + 1, 12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds client->addr + W83781D_ADDR_REG_OFFSET); 12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = 12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (res << 8) + inb_p(client->addr + 12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds W83781D_DATA_REG_OFFSET); 12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (reg & 0xff00) { 12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(W83781D_REG_BANK, 12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds client->addr + W83781D_ADDR_REG_OFFSET); 12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); 12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up(&data->lock); 12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return res; 12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int w83627thf_read_gpio5(struct i2c_client *client) 12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int res = 0xff, sel; 12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds superio_enter(); 12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds superio_select(W83627HF_LD_GPIO5); 12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Make sure these GPIO pins are enabled */ 12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(superio_inb(W83627THF_GPIO5_EN) & (1<<3))) { 12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_dbg(&client->dev, "GPIO5 disabled, no VID function\n"); 12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Make sure the pins are configured for input 12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds There must be at least five (VRM 9), and possibly 6 (VRM 10) */ 12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sel = superio_inb(W83627THF_GPIO5_IOSR); 12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((sel & 0x1f) != 0x1f) { 12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_dbg(&client->dev, "GPIO5 not configured for VID " 12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "function\n"); 12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto exit; 12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_info(&client->dev, "Reading VID from GPIO5\n"); 12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = superio_inb(W83627THF_GPIO5_DR) & sel; 12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsexit: 12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds superio_exit(); 12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return res; 12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int w83627hf_write_value(struct i2c_client *client, u16 reg, u16 value) 12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct w83627hf_data *data = i2c_get_clientdata(client); 12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int word_sized; 12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds down(&data->lock); 12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds word_sized = (((reg & 0xff00) == 0x100) 12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || ((reg & 0xff00) == 0x200)) 12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (((reg & 0x00ff) == 0x53) 12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || ((reg & 0x00ff) == 0x55)); 12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (reg & 0xff00) { 12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(W83781D_REG_BANK, 12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds client->addr + W83781D_ADDR_REG_OFFSET); 12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(reg >> 8, 12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds client->addr + W83781D_DATA_REG_OFFSET); 12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(reg & 0xff, client->addr + W83781D_ADDR_REG_OFFSET); 12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (word_sized) { 12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(value >> 8, 12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds client->addr + W83781D_DATA_REG_OFFSET); 12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p((reg & 0xff) + 1, 12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds client->addr + W83781D_ADDR_REG_OFFSET); 12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(value & 0xff, 12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds client->addr + W83781D_DATA_REG_OFFSET); 12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (reg & 0xff00) { 12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(W83781D_REG_BANK, 12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds client->addr + W83781D_ADDR_REG_OFFSET); 12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(0, client->addr + W83781D_DATA_REG_OFFSET); 12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up(&data->lock); 12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void w83627hf_init_client(struct i2c_client *client) 12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct w83627hf_data *data = i2c_get_clientdata(client); 12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int type = data->type; 12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 tmp; 12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12902251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare if (reset) { 12912251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare /* Resetting the chip has been the default for a long time, 12922251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare but repeatedly caused problems (fans going to full 12932251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare speed...) so it is now optional. It might even go away if 12942251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare nobody reports it as being useful, as I see very little 12952251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare reason why this would be needed at all. */ 12962251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare dev_info(&client->dev, "If reset=1 solved a problem you were " 12972251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare "having, please report!\n"); 12982251cf1a4b37bd483501614c2d78f5b8286f20d7Jean Delvare 12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* save this register */ 13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = w83627hf_read_value(client, W83781D_REG_BEEP_CONFIG); 13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Reset all except Watchdog values and last conversion values 13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This sets fan-divs to 2, among others */ 13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_write_value(client, W83781D_REG_CONFIG, 0x80); 13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Restore the register and disable power-on abnormal beep. 13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This saves FAN 1/2/3 input/output values set by BIOS. */ 13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_write_value(client, W83781D_REG_BEEP_CONFIG, i | 0x80); 13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Disable master beep-enable (reset turns it on). 13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Individual beeps should be reset to off but for some reason 13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds disabling this bit helps some people not get beeped */ 13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_write_value(client, W83781D_REG_BEEP_INTS2, 0); 13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Minimize conflicts with other winbond i2c-only clients... */ 13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* disable i2c subclients... how to disable main i2c client?? */ 13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* force i2c address to relatively uncommon address */ 13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_write_value(client, W83781D_REG_I2C_SUBADDR, 0x89); 13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_write_value(client, W83781D_REG_I2C_ADDR, force_i2c); 13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Read VID only once */ 13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (w83627hf == data->type || w83637hf == data->type) { 13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int lo = w83627hf_read_value(client, W83781D_REG_VID_FANDIV); 13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int hi = w83627hf_read_value(client, W83781D_REG_CHIPID); 13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->vid = (lo & 0x0f) | ((hi & 0x01) << 4); 13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else if (w83627thf == data->type) { 13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->vid = w83627thf_read_gpio5(client) & 0x3f; 13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Read VRM & OVT Config only once */ 13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (w83627thf == data->type || w83637hf == data->type) { 13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->vrm_ovt = 13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_read_value(client, W83627THF_REG_VRM_OVT_CFG); 13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->vrm = (data->vrm_ovt & 0x01) ? 90 : 82; 13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Convert VID to voltage based on default VRM */ 1335303760b44a7a142cb9f4c9df4609fb63bbda98dbJean Delvare data->vrm = vid_which_vrm(); 13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = w83627hf_read_value(client, W83781D_REG_SCFG1); 13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 1; i <= 3; i++) { 13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(tmp & BIT_SCFG1[i - 1])) { 13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->sens[i - 1] = W83781D_DEFAULT_BETA; 13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (w83627hf_read_value 13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (client, 13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds W83781D_REG_SCFG2) & BIT_SCFG2[i - 1]) 13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->sens[i - 1] = 1; 13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->sens[i - 1] = 2; 13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((type == w83697hf) && (i == 2)) 13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(init) { 13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Enable temp2 */ 13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = w83627hf_read_value(client, W83781D_REG_TEMP2_CONFIG); 13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tmp & 0x01) { 13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_warn(&client->dev, "Enabling temp2, readings " 13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "might not make sense\n"); 13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_write_value(client, W83781D_REG_TEMP2_CONFIG, 13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp & 0xfe); 13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Enable temp3 */ 13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (type != w83697hf) { 13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = w83627hf_read_value(client, 13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds W83781D_REG_TEMP3_CONFIG); 13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tmp & 0x01) { 13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_warn(&client->dev, "Enabling temp3, " 13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "readings might not make sense\n"); 13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_write_value(client, 13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds W83781D_REG_TEMP3_CONFIG, tmp & 0xfe); 13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (type == w83627hf) { 13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* enable PWM2 control (can't hurt since PWM reg 13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds should have been reset to 0xff) */ 13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_write_value(client, W83627HF_REG_PWMCLK12, 13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x19); 13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* enable comparator mode for temp2 and temp3 so 13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds alarm indication will work correctly */ 13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = w83627hf_read_value(client, W83781D_REG_IRQ); 13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(i & 0x40)) 13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_write_value(client, W83781D_REG_IRQ, 13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i | 0x40); 13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Start monitoring */ 13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_write_value(client, W83781D_REG_CONFIG, 13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (w83627hf_read_value(client, 13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds W83781D_REG_CONFIG) & 0xf7) 13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | 0x01); 13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct w83627hf_data *w83627hf_update_device(struct device *dev) 13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct i2c_client *client = to_i2c_client(dev); 14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct w83627hf_data *data = i2c_get_clientdata(client); 14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds down(&data->update_lock); 14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (time_after(jiffies, data->last_updated + HZ + HZ / 2) 14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || !data->valid) { 14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i <= 8; i++) { 14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* skip missing sensors */ 14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (((data->type == w83697hf) && (i == 1)) || 14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((data->type == w83627thf || data->type == w83637hf) 14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (i == 4 || i == 5))) 14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->in[i] = 14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_read_value(client, W83781D_REG_IN(i)); 14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->in_min[i] = 14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_read_value(client, 14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds W83781D_REG_IN_MIN(i)); 14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->in_max[i] = 14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_read_value(client, 14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds W83781D_REG_IN_MAX(i)); 14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 1; i <= 3; i++) { 14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fan[i - 1] = 14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_read_value(client, W83781D_REG_FAN(i)); 14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fan_min[i - 1] = 14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_read_value(client, 14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds W83781D_REG_FAN_MIN(i)); 14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 1; i <= 3; i++) { 14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 tmp = w83627hf_read_value(client, 14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds W836X7HF_REG_PWM(data->type, i)); 14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* bits 0-3 are reserved in 627THF */ 14331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->type == w83627thf) 14341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp &= 0xf0; 14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->pwm[i - 1] = tmp; 14361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if(i == 2 && 14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (data->type == w83627hf || data->type == w83697hf)) 14381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->temp = w83627hf_read_value(client, W83781D_REG_TEMP(1)); 14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->temp_max = 14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_read_value(client, W83781D_REG_TEMP_OVER(1)); 14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->temp_max_hyst = 14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_read_value(client, W83781D_REG_TEMP_HYST(1)); 14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->temp_add[0] = 14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_read_value(client, W83781D_REG_TEMP(2)); 14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->temp_max_add[0] = 14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_read_value(client, W83781D_REG_TEMP_OVER(2)); 14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->temp_max_hyst_add[0] = 14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_read_value(client, W83781D_REG_TEMP_HYST(2)); 14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->type != w83697hf) { 14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->temp_add[1] = 14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_read_value(client, W83781D_REG_TEMP(3)); 14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->temp_max_add[1] = 14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_read_value(client, W83781D_REG_TEMP_OVER(3)); 14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->temp_max_hyst_add[1] = 14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_read_value(client, W83781D_REG_TEMP_HYST(3)); 14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = w83627hf_read_value(client, W83781D_REG_VID_FANDIV); 14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fan_div[0] = (i >> 4) & 0x03; 14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fan_div[1] = (i >> 6) & 0x03; 14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->type != w83697hf) { 14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fan_div[2] = (w83627hf_read_value(client, 14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds W83781D_REG_PIN) >> 6) & 0x03; 14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = w83627hf_read_value(client, W83781D_REG_VBAT); 14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fan_div[0] |= (i >> 3) & 0x04; 14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fan_div[1] |= (i >> 4) & 0x04; 14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->type != w83697hf) 14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fan_div[2] |= (i >> 5) & 0x04; 14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->alarms = 14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_read_value(client, W83781D_REG_ALARM1) | 14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (w83627hf_read_value(client, W83781D_REG_ALARM2) << 8) | 14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (w83627hf_read_value(client, W83781D_REG_ALARM3) << 16); 14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = w83627hf_read_value(client, W83781D_REG_BEEP_INTS2); 14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->beep_enable = i >> 7; 14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->beep_mask = ((i & 0x7f) << 8) | 14801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_read_value(client, W83781D_REG_BEEP_INTS1) | 14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds w83627hf_read_value(client, W83781D_REG_BEEP_INTS3) << 16; 14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->last_updated = jiffies; 14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->valid = 1; 14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds up(&data->update_lock); 14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return data; 14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init sensors_w83627hf_init(void) 14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14932d8672c5a6ba0d3f1d8d3ad61ef67868941364f0Jean Delvare if (w83627hf_find(0x2e, &address) 14942d8672c5a6ba0d3f1d8d3ad61ef67868941364f0Jean Delvare && w83627hf_find(0x4e, &address)) { 14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1498fde0950903ce8cc38a91dd095280decceda2ff82Jean Delvare return i2c_isa_add_driver(&w83627hf_driver); 14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit sensors_w83627hf_exit(void) 15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1503fde0950903ce8cc38a91dd095280decceda2ff82Jean Delvare i2c_isa_del_driver(&w83627hf_driver); 15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>, " 15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "Philip Edelbrock <phil@netroedge.com>, " 15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "and Mark Studebaker <mdsxyz123@yahoo.com>"); 15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("W83627HF driver"); 15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(sensors_w83627hf_init); 15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(sensors_w83627hf_exit); 1514