11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pc87360.c - Part of lm_sensors, Linux kernel modules 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for hardware monitoring 4f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare * Copyright (C) 2004, 2007 Jean Delvare <khali@linux-fr.org> 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copied from smsc47m1.c: 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com> 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 * Supports the following chips: 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Chip #vin #fan #pwm #temp devid 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PC87360 - 2 2 - 0xE1 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PC87363 - 2 2 - 0xE8 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PC87364 - 3 3 - 0xE4 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PC87365 11 3 3 2 0xE5 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PC87366 11 3 3 3-4 0xE9 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This driver assumes that no more than one chip is present, and one of 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the standard Super-I/O addresses is used (0x2E/0x2F or 0x4E/0x4F). 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 369e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 379e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/jiffies.h> 42f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare#include <linux/platform_device.h> 43943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman#include <linux/hwmon.h> 44f0986bd8f390392948db85dac526fb238752372bJim Cromie#include <linux/hwmon-sysfs.h> 45303760b44a7a142cb9f4c9df4609fb63bbda98dbJean Delvare#include <linux/hwmon-vid.h> 46943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman#include <linux/err.h> 479a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar#include <linux/mutex.h> 48b9acb64a385c5b26fc392e0d58ac7b8e0a2cd812Jean Delvare#include <linux/acpi.h> 496055fae8aceee41471edfd1876e5617d16e028feH Hartley Sweeten#include <linux/io.h> 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u8 devid; 52f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvarestatic struct platform_device *pdev; 532d8672c5a6ba0d3f1d8d3ad61ef67868941364f0Jean Delvarestatic unsigned short extra_isa[3]; 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic u8 confreg[4]; 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int init = 1; 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(init, int, 0); 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(init, 59449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck"Chip initialization level:\n" 60449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck" 0: None\n" 61449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck"*1: Forcibly enable internal voltage and temperature channels, except in9\n" 62449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck" 2: Forcibly enable all voltage and temperature channels, except in9\n" 63449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck" 3: Forcibly enable all voltage and temperature channels, including in9"); 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6567b671bceb4a8340a30929e9642620d99ed5ad76Jean Delvarestatic unsigned short force_id; 6667b671bceb4a8340a30929e9642620d99ed5ad76Jean Delvaremodule_param(force_id, ushort, 0); 6767b671bceb4a8340a30929e9642620d99ed5ad76Jean DelvareMODULE_PARM_DESC(force_id, "Override the detected device ID"); 6867b671bceb4a8340a30929e9642620d99ed5ad76Jean Delvare 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Super-I/O registers and operations 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DEV 0x07 /* Register: Logical device select */ 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DEVID 0x20 /* Register: Device ID */ 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ACT 0x30 /* Register: Device activation */ 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define BASE 0x60 /* Register: Base address */ 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FSCM 0x09 /* Logical device: fans */ 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VLM 0x0d /* Logical device: voltages */ 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TMS 0x0e /* Logical device: temperatures */ 812a32ec2500514109754e07721d9d5d431a706a31Jim Cromie#define LDNI_MAX 3 822a32ec2500514109754e07721d9d5d431a706a31Jim Cromiestatic const u8 logdev[LDNI_MAX] = { FSCM, VLM, TMS }; 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LD_FAN 0 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LD_IN 1 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LD_TEMP 2 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void superio_outb(int sioaddr, int reg, int val) 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(reg, sioaddr); 91449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck outb(val, sioaddr + 1); 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int superio_inb(int sioaddr, int reg) 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(reg, sioaddr); 97449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck return inb(sioaddr + 1); 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void superio_exit(int sioaddr) 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0x02, sioaddr); 103449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck outb(0x02, sioaddr + 1); 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Logical devices 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87360_EXTENT 0x10 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87365_REG_BANK 0x09 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define NO_BANK 0xff 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Fan registers and conversions 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* nr has to be 0 or 1 (PC87360/87363) or 2 (PC87364/87365/87366) */ 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87360_REG_PRESCALE(nr) (0x00 + 2 * (nr)) 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87360_REG_PWM(nr) (0x01 + 2 * (nr)) 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87360_REG_FAN_MIN(nr) (0x06 + 3 * (nr)) 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87360_REG_FAN(nr) (0x07 + 3 * (nr)) 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87360_REG_FAN_STATUS(nr) (0x08 + 3 * (nr)) 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 125449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck#define FAN_FROM_REG(val, div) ((val) == 0 ? 0 : \ 126449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck 480000 / ((val) * (div))) 127449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck#define FAN_TO_REG(val, div) ((val) <= 100 ? 0 : \ 128449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck 480000 / ((val) * (div))) 129449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck#define FAN_DIV_FROM_REG(val) (1 << (((val) >> 5) & 0x03)) 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FAN_STATUS_FROM_REG(val) ((val) & 0x07) 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 132449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck#define FAN_CONFIG_MONITOR(val, nr) (((val) >> (2 + (nr) * 3)) & 1) 133449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck#define FAN_CONFIG_CONTROL(val, nr) (((val) >> (3 + (nr) * 3)) & 1) 134449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck#define FAN_CONFIG_INVERT(val, nr) (((val) >> (4 + (nr) * 3)) & 1) 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 136449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck#define PWM_FROM_REG(val, inv) ((inv) ? 255 - (val) : (val)) 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u8 PWM_TO_REG(int val, int inv) 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (inv) 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = 255 - val; 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (val < 0) 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (val > 255) 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 255; 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return val; 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Voltage registers and conversions 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87365_REG_IN_CONVRATE 0x07 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87365_REG_IN_CONFIG 0x08 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87365_REG_IN 0x0B 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87365_REG_IN_MIN 0x0D 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87365_REG_IN_MAX 0x0C 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87365_REG_IN_STATUS 0x0A 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87365_REG_IN_ALARMS1 0x00 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87365_REG_IN_ALARMS2 0x01 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87365_REG_VID 0x06 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 162449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck#define IN_FROM_REG(val, ref) (((val) * (ref) + 128) / 256) 163449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck#define IN_TO_REG(val, ref) ((val) < 0 ? 0 : \ 164449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck (val) * 256 >= (ref) * 255 ? 255 : \ 165449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck ((val) * 256 + (ref) / 2) / (ref)) 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Temperature registers and conversions 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87365_REG_TEMP_CONFIG 0x08 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87365_REG_TEMP 0x0B 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87365_REG_TEMP_MIN 0x0D 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87365_REG_TEMP_MAX 0x0C 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87365_REG_TEMP_CRIT 0x0E 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87365_REG_TEMP_STATUS 0x0A 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PC87365_REG_TEMP_ALARMS 0x00 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEMP_FROM_REG(val) ((val) * 1000) 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TEMP_TO_REG(val) ((val) < -55000 ? -55 : \ 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (val) > 127000 ? 127 : \ 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (val) < 0 ? ((val) - 500) / 1000 : \ 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((val) + 500) / 1000) 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 186f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare * Device data 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct pc87360_data { 190f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare const char *name; 1911beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones struct device *hwmon_dev; 1929a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar struct mutex lock; 1939a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar struct mutex update_lock; 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char valid; /* !=0 if following fields are valid */ 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long last_updated; /* In jiffies */ 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int address[3]; 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 fannr, innr, tempnr; 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 fan[3]; /* Register value */ 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 fan_min[3]; /* Register value */ 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 fan_status[3]; /* Register value */ 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 pwm[3]; /* Register value */ 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 fan_conf; /* Configuration register values, combined */ 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 in_vref; /* 1 mV/bit */ 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 in[14]; /* Register value */ 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 in_min[14]; /* Register value */ 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 in_max[14]; /* Register value */ 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 in_crit[3]; /* Register value */ 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 in_status[14]; /* Register value */ 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 in_alarms; /* Register values, combined, masked */ 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 vid_conf; /* Configuration register value */ 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 vrm; 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 vid; /* Register value */ 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s8 temp[3]; /* Register value */ 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s8 temp_min[3]; /* Register value */ 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s8 temp_max[3]; /* Register value */ 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s8 temp_crit[3]; /* Register value */ 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 temp_status[3]; /* Register value */ 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 temp_alarms; /* Register value, masked */ 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Functions declaration 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 230f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvarestatic int pc87360_probe(struct platform_device *pdev); 231d0546128980c18748010c758903b02909e634830Jean Delvarestatic int __devexit pc87360_remove(struct platform_device *pdev); 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank, 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 reg); 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank, 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 reg, u8 value); 237f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvarestatic void pc87360_init_device(struct platform_device *pdev, 238f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare int use_thermistors); 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pc87360_data *pc87360_update_device(struct device *dev); 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 242f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare * Driver data 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 245f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvarestatic struct platform_driver pc87360_driver = { 246cdaf79349c7d24e1d33acb6497849c9e956a33eaLaurent Riffard .driver = { 247872188420997f7f7c1b968fd9bce6578e4c3d45fJean Delvare .owner = THIS_MODULE, 248cdaf79349c7d24e1d33acb6497849c9e956a33eaLaurent Riffard .name = "pc87360", 249cdaf79349c7d24e1d33acb6497849c9e956a33eaLaurent Riffard }, 250f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare .probe = pc87360_probe, 251f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare .remove = __devexit_p(pc87360_remove), 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Sysfs stuff 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 258449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_fan_input(struct device *dev, 259449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck struct device_attribute *devattr, char *buf) 260f0986bd8f390392948db85dac526fb238752372bJim Cromie{ 261f0986bd8f390392948db85dac526fb238752372bJim Cromie struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 262f0986bd8f390392948db85dac526fb238752372bJim Cromie struct pc87360_data *data = pc87360_update_device(dev); 263694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan[attr->index], 264694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie FAN_DIV_FROM_REG(data->fan_status[attr->index]))); 265f0986bd8f390392948db85dac526fb238752372bJim Cromie} 266449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_fan_min(struct device *dev, 267449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck struct device_attribute *devattr, char *buf) 268f0986bd8f390392948db85dac526fb238752372bJim Cromie{ 269f0986bd8f390392948db85dac526fb238752372bJim Cromie struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 270f0986bd8f390392948db85dac526fb238752372bJim Cromie struct pc87360_data *data = pc87360_update_device(dev); 271694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie return sprintf(buf, "%u\n", FAN_FROM_REG(data->fan_min[attr->index], 272694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie FAN_DIV_FROM_REG(data->fan_status[attr->index]))); 273f0986bd8f390392948db85dac526fb238752372bJim Cromie} 274449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_fan_div(struct device *dev, 275449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck struct device_attribute *devattr, char *buf) 276f0986bd8f390392948db85dac526fb238752372bJim Cromie{ 277f0986bd8f390392948db85dac526fb238752372bJim Cromie struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 278f0986bd8f390392948db85dac526fb238752372bJim Cromie struct pc87360_data *data = pc87360_update_device(dev); 279f0986bd8f390392948db85dac526fb238752372bJim Cromie return sprintf(buf, "%u\n", 280694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie FAN_DIV_FROM_REG(data->fan_status[attr->index])); 281f0986bd8f390392948db85dac526fb238752372bJim Cromie} 282449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_fan_status(struct device *dev, 283449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck struct device_attribute *devattr, char *buf) 284f0986bd8f390392948db85dac526fb238752372bJim Cromie{ 285f0986bd8f390392948db85dac526fb238752372bJim Cromie struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 286f0986bd8f390392948db85dac526fb238752372bJim Cromie struct pc87360_data *data = pc87360_update_device(dev); 287f0986bd8f390392948db85dac526fb238752372bJim Cromie return sprintf(buf, "%u\n", 288694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie FAN_STATUS_FROM_REG(data->fan_status[attr->index])); 289f0986bd8f390392948db85dac526fb238752372bJim Cromie} 290449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t set_fan_min(struct device *dev, 291449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck struct device_attribute *devattr, const char *buf, 292f0986bd8f390392948db85dac526fb238752372bJim Cromie size_t count) 293f0986bd8f390392948db85dac526fb238752372bJim Cromie{ 294f0986bd8f390392948db85dac526fb238752372bJim Cromie struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 295f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare struct pc87360_data *data = dev_get_drvdata(dev); 296449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck long fan_min; 297449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck int err; 298449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck 299449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck err = kstrtol(buf, 10, &fan_min); 300449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck if (err) 301449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck return err; 30211be27ea9bfd0ea7bca797ba6937285d18d426c2Jim Cromie 3039a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_lock(&data->update_lock); 304449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck fan_min = FAN_TO_REG(fan_min, 305449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck FAN_DIV_FROM_REG(data->fan_status[attr->index])); 30611be27ea9bfd0ea7bca797ba6937285d18d426c2Jim Cromie 30711be27ea9bfd0ea7bca797ba6937285d18d426c2Jim Cromie /* If it wouldn't fit, change clock divisor */ 30811be27ea9bfd0ea7bca797ba6937285d18d426c2Jim Cromie while (fan_min > 255 30911be27ea9bfd0ea7bca797ba6937285d18d426c2Jim Cromie && (data->fan_status[attr->index] & 0x60) != 0x60) { 31011be27ea9bfd0ea7bca797ba6937285d18d426c2Jim Cromie fan_min >>= 1; 31111be27ea9bfd0ea7bca797ba6937285d18d426c2Jim Cromie data->fan[attr->index] >>= 1; 31211be27ea9bfd0ea7bca797ba6937285d18d426c2Jim Cromie data->fan_status[attr->index] += 0x20; 31311be27ea9bfd0ea7bca797ba6937285d18d426c2Jim Cromie } 31411be27ea9bfd0ea7bca797ba6937285d18d426c2Jim Cromie data->fan_min[attr->index] = fan_min > 255 ? 255 : fan_min; 315449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck pc87360_write_value(data, LD_FAN, NO_BANK, 316449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck PC87360_REG_FAN_MIN(attr->index), 31711be27ea9bfd0ea7bca797ba6937285d18d426c2Jim Cromie data->fan_min[attr->index]); 31811be27ea9bfd0ea7bca797ba6937285d18d426c2Jim Cromie 31911be27ea9bfd0ea7bca797ba6937285d18d426c2Jim Cromie /* Write new divider, preserve alarm bits */ 320449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck pc87360_write_value(data, LD_FAN, NO_BANK, 321449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck PC87360_REG_FAN_STATUS(attr->index), 32211be27ea9bfd0ea7bca797ba6937285d18d426c2Jim Cromie data->fan_status[attr->index] & 0xF9); 3239a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_unlock(&data->update_lock); 32411be27ea9bfd0ea7bca797ba6937285d18d426c2Jim Cromie 32511be27ea9bfd0ea7bca797ba6937285d18d426c2Jim Cromie return count; 326f0986bd8f390392948db85dac526fb238752372bJim Cromie} 327f0986bd8f390392948db85dac526fb238752372bJim Cromie 328dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute fan_input[] = { 329dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(fan1_input, S_IRUGO, show_fan_input, NULL, 0), 330dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(fan2_input, S_IRUGO, show_fan_input, NULL, 1), 331dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(fan3_input, S_IRUGO, show_fan_input, NULL, 2), 332dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie}; 333dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute fan_status[] = { 334dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(fan1_status, S_IRUGO, show_fan_status, NULL, 0), 335dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(fan2_status, S_IRUGO, show_fan_status, NULL, 1), 336dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(fan3_status, S_IRUGO, show_fan_status, NULL, 2), 337dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie}; 338dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute fan_div[] = { 339dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(fan1_div, S_IRUGO, show_fan_div, NULL, 0), 340dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(fan2_div, S_IRUGO, show_fan_div, NULL, 1), 341dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2), 342dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie}; 343dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute fan_min[] = { 344dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min, set_fan_min, 0), 345dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min, set_fan_min, 1), 346dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min, set_fan_min, 2), 347dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie}; 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 349bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck#define FAN_UNIT_ATTRS(X) \ 350bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck{ &fan_input[X].dev_attr.attr, \ 351941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie &fan_status[X].dev_attr.attr, \ 352941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie &fan_div[X].dev_attr.attr, \ 353bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck &fan_min[X].dev_attr.attr, \ 354bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck NULL \ 355bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck} 356941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie 357449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, 358449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck char *buf) 359f0986bd8f390392948db85dac526fb238752372bJim Cromie{ 360f0986bd8f390392948db85dac526fb238752372bJim Cromie struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 361f0986bd8f390392948db85dac526fb238752372bJim Cromie struct pc87360_data *data = pc87360_update_device(dev); 362f0986bd8f390392948db85dac526fb238752372bJim Cromie return sprintf(buf, "%u\n", 363694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie PWM_FROM_REG(data->pwm[attr->index], 364f0986bd8f390392948db85dac526fb238752372bJim Cromie FAN_CONFIG_INVERT(data->fan_conf, 365694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie attr->index))); 366f0986bd8f390392948db85dac526fb238752372bJim Cromie} 367449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t set_pwm(struct device *dev, struct device_attribute *devattr, 368449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck const char *buf, size_t count) 369f0986bd8f390392948db85dac526fb238752372bJim Cromie{ 370f0986bd8f390392948db85dac526fb238752372bJim Cromie struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 371f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare struct pc87360_data *data = dev_get_drvdata(dev); 372449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck long val; 373449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck int err; 374449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck 375449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck err = kstrtol(buf, 10, &val); 376449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck if (err) 377449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck return err; 378f0986bd8f390392948db85dac526fb238752372bJim Cromie 3799a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_lock(&data->update_lock); 380694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie data->pwm[attr->index] = PWM_TO_REG(val, 381694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie FAN_CONFIG_INVERT(data->fan_conf, attr->index)); 382694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie pc87360_write_value(data, LD_FAN, NO_BANK, PC87360_REG_PWM(attr->index), 383694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie data->pwm[attr->index]); 3849a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_unlock(&data->update_lock); 385f0986bd8f390392948db85dac526fb238752372bJim Cromie return count; 386f0986bd8f390392948db85dac526fb238752372bJim Cromie} 387f0986bd8f390392948db85dac526fb238752372bJim Cromie 388dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute pwm[] = { 389dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 0), 390dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 1), 391dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2), 392dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie}; 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 394bce2778df9ea32146d59344c027001e270911f4bGuenter Roeckstatic struct attribute *pc8736x_fan_attr[][5] = { 395941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie FAN_UNIT_ATTRS(0), 396941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie FAN_UNIT_ATTRS(1), 397bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck FAN_UNIT_ATTRS(2) 398941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie}; 399bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck 400bce2778df9ea32146d59344c027001e270911f4bGuenter Roeckstatic const struct attribute_group pc8736x_fan_attr_group[] = { 401bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck { .attrs = pc8736x_fan_attr[0], }, 402bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck { .attrs = pc8736x_fan_attr[1], }, 403bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck { .attrs = pc8736x_fan_attr[2], }, 404941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie}; 405941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie 406449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_in_input(struct device *dev, 407449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck struct device_attribute *devattr, char *buf) 408f0986bd8f390392948db85dac526fb238752372bJim Cromie{ 409f0986bd8f390392948db85dac526fb238752372bJim Cromie struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 410f0986bd8f390392948db85dac526fb238752372bJim Cromie struct pc87360_data *data = pc87360_update_device(dev); 411f0986bd8f390392948db85dac526fb238752372bJim Cromie return sprintf(buf, "%u\n", IN_FROM_REG(data->in[attr->index], 412f0986bd8f390392948db85dac526fb238752372bJim Cromie data->in_vref)); 413f0986bd8f390392948db85dac526fb238752372bJim Cromie} 414449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_in_min(struct device *dev, 415449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck struct device_attribute *devattr, char *buf) 416f0986bd8f390392948db85dac526fb238752372bJim Cromie{ 417f0986bd8f390392948db85dac526fb238752372bJim Cromie struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 418f0986bd8f390392948db85dac526fb238752372bJim Cromie struct pc87360_data *data = pc87360_update_device(dev); 419f0986bd8f390392948db85dac526fb238752372bJim Cromie return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[attr->index], 420f0986bd8f390392948db85dac526fb238752372bJim Cromie data->in_vref)); 421f0986bd8f390392948db85dac526fb238752372bJim Cromie} 422449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_in_max(struct device *dev, 423449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck struct device_attribute *devattr, char *buf) 424f0986bd8f390392948db85dac526fb238752372bJim Cromie{ 425f0986bd8f390392948db85dac526fb238752372bJim Cromie struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 426f0986bd8f390392948db85dac526fb238752372bJim Cromie struct pc87360_data *data = pc87360_update_device(dev); 427f0986bd8f390392948db85dac526fb238752372bJim Cromie return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[attr->index], 428f0986bd8f390392948db85dac526fb238752372bJim Cromie data->in_vref)); 429f0986bd8f390392948db85dac526fb238752372bJim Cromie} 430449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_in_status(struct device *dev, 431449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck struct device_attribute *devattr, char *buf) 432f0986bd8f390392948db85dac526fb238752372bJim Cromie{ 433f0986bd8f390392948db85dac526fb238752372bJim Cromie struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 434f0986bd8f390392948db85dac526fb238752372bJim Cromie struct pc87360_data *data = pc87360_update_device(dev); 435f0986bd8f390392948db85dac526fb238752372bJim Cromie return sprintf(buf, "%u\n", data->in_status[attr->index]); 436f0986bd8f390392948db85dac526fb238752372bJim Cromie} 437449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t set_in_min(struct device *dev, struct device_attribute *devattr, 438449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck const char *buf, size_t count) 439f0986bd8f390392948db85dac526fb238752372bJim Cromie{ 440f0986bd8f390392948db85dac526fb238752372bJim Cromie struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 441f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare struct pc87360_data *data = dev_get_drvdata(dev); 442449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck long val; 443449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck int err; 444449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck 445449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck err = kstrtol(buf, 10, &val); 446449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck if (err) 447449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck return err; 448f0986bd8f390392948db85dac526fb238752372bJim Cromie 4499a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_lock(&data->update_lock); 450f0986bd8f390392948db85dac526fb238752372bJim Cromie data->in_min[attr->index] = IN_TO_REG(val, data->in_vref); 451f0986bd8f390392948db85dac526fb238752372bJim Cromie pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_IN_MIN, 452f0986bd8f390392948db85dac526fb238752372bJim Cromie data->in_min[attr->index]); 4539a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_unlock(&data->update_lock); 454f0986bd8f390392948db85dac526fb238752372bJim Cromie return count; 455f0986bd8f390392948db85dac526fb238752372bJim Cromie} 456449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t set_in_max(struct device *dev, struct device_attribute *devattr, 457449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck const char *buf, size_t count) 458f0986bd8f390392948db85dac526fb238752372bJim Cromie{ 459f0986bd8f390392948db85dac526fb238752372bJim Cromie struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 460f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare struct pc87360_data *data = dev_get_drvdata(dev); 461449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck long val; 462449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck int err; 463449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck 464449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck err = kstrtol(buf, 10, &val); 465449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck if (err) 466449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck return err; 467f0986bd8f390392948db85dac526fb238752372bJim Cromie 4689a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_lock(&data->update_lock); 469f0986bd8f390392948db85dac526fb238752372bJim Cromie data->in_max[attr->index] = IN_TO_REG(val, 470f0986bd8f390392948db85dac526fb238752372bJim Cromie data->in_vref); 471f0986bd8f390392948db85dac526fb238752372bJim Cromie pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_IN_MAX, 472f0986bd8f390392948db85dac526fb238752372bJim Cromie data->in_max[attr->index]); 4739a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_unlock(&data->update_lock); 474f0986bd8f390392948db85dac526fb238752372bJim Cromie return count; 475f0986bd8f390392948db85dac526fb238752372bJim Cromie} 476f0986bd8f390392948db85dac526fb238752372bJim Cromie 477dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute in_input[] = { 478dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in0_input, S_IRUGO, show_in_input, NULL, 0), 479dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in1_input, S_IRUGO, show_in_input, NULL, 1), 480dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in2_input, S_IRUGO, show_in_input, NULL, 2), 481dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in3_input, S_IRUGO, show_in_input, NULL, 3), 482dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in4_input, S_IRUGO, show_in_input, NULL, 4), 483dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in5_input, S_IRUGO, show_in_input, NULL, 5), 484dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in6_input, S_IRUGO, show_in_input, NULL, 6), 485dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in7_input, S_IRUGO, show_in_input, NULL, 7), 486dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in8_input, S_IRUGO, show_in_input, NULL, 8), 487dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in9_input, S_IRUGO, show_in_input, NULL, 9), 488dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in10_input, S_IRUGO, show_in_input, NULL, 10), 489dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie}; 490dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute in_status[] = { 491dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in0_status, S_IRUGO, show_in_status, NULL, 0), 492dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in1_status, S_IRUGO, show_in_status, NULL, 1), 493dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in2_status, S_IRUGO, show_in_status, NULL, 2), 494dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in3_status, S_IRUGO, show_in_status, NULL, 3), 495dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in4_status, S_IRUGO, show_in_status, NULL, 4), 496dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in5_status, S_IRUGO, show_in_status, NULL, 5), 497dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in6_status, S_IRUGO, show_in_status, NULL, 6), 498dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in7_status, S_IRUGO, show_in_status, NULL, 7), 499dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in8_status, S_IRUGO, show_in_status, NULL, 8), 500dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in9_status, S_IRUGO, show_in_status, NULL, 9), 501dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in10_status, S_IRUGO, show_in_status, NULL, 10), 502dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie}; 503dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute in_min[] = { 504dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in0_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 0), 505dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in1_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 1), 506dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in2_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 2), 507dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in3_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 3), 508dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in4_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 4), 509dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in5_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 5), 510dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in6_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 6), 511dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in7_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 7), 512dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in8_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 8), 513dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in9_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 9), 514dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in10_min, S_IWUSR | S_IRUGO, show_in_min, set_in_min, 10), 515dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie}; 516dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute in_max[] = { 517dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in0_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 0), 518dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in1_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 1), 519dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in2_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 2), 520dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in3_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 3), 521dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in4_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 4), 522dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in5_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 5), 523dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in6_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 6), 524dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in7_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 7), 525dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in8_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 8), 526dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in9_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 9), 527dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(in10_max, S_IWUSR | S_IRUGO, show_in_max, set_in_max, 10), 528dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie}; 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 53028f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie/* (temp & vin) channel status register alarm bits (pdf sec.11.5.12) */ 53128f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie#define CHAN_ALM_MIN 0x02 /* min limit crossed */ 53228f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie#define CHAN_ALM_MAX 0x04 /* max limit exceeded */ 53328f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie#define TEMP_ALM_CRIT 0x08 /* temp crit exceeded (temp only) */ 53428f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie 5353af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck/* 5363af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * show_in_min/max_alarm() reads data from the per-channel status 5373af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * register (sec 11.5.12), not the vin event status registers (sec 5383af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * 11.5.2) that (legacy) show_in_alarm() resds (via data->in_alarms) 5393af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck */ 540492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie 541492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromiestatic ssize_t show_in_min_alarm(struct device *dev, 542492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie struct device_attribute *devattr, char *buf) 543492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie{ 544492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie struct pc87360_data *data = pc87360_update_device(dev); 545492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie unsigned nr = to_sensor_dev_attr(devattr)->index; 546492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie 547492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie return sprintf(buf, "%u\n", !!(data->in_status[nr] & CHAN_ALM_MIN)); 548492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie} 549492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromiestatic ssize_t show_in_max_alarm(struct device *dev, 550492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie struct device_attribute *devattr, char *buf) 551492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie{ 552492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie struct pc87360_data *data = pc87360_update_device(dev); 553492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie unsigned nr = to_sensor_dev_attr(devattr)->index; 554492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie 555492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie return sprintf(buf, "%u\n", !!(data->in_status[nr] & CHAN_ALM_MAX)); 556492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie} 557492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie 558492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromiestatic struct sensor_device_attribute in_min_alarm[] = { 559492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie SENSOR_ATTR(in0_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 0), 560492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie SENSOR_ATTR(in1_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 1), 561492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie SENSOR_ATTR(in2_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 2), 562492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie SENSOR_ATTR(in3_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 3), 563492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie SENSOR_ATTR(in4_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 4), 564492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie SENSOR_ATTR(in5_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 5), 565492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie SENSOR_ATTR(in6_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 6), 566492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie SENSOR_ATTR(in7_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 7), 567492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie SENSOR_ATTR(in8_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 8), 568492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie SENSOR_ATTR(in9_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 9), 569492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie SENSOR_ATTR(in10_min_alarm, S_IRUGO, show_in_min_alarm, NULL, 10), 570492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie}; 571492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromiestatic struct sensor_device_attribute in_max_alarm[] = { 572492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie SENSOR_ATTR(in0_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 0), 573492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie SENSOR_ATTR(in1_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 1), 574492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie SENSOR_ATTR(in2_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 2), 575492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie SENSOR_ATTR(in3_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 3), 576492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie SENSOR_ATTR(in4_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 4), 577492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie SENSOR_ATTR(in5_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 5), 578492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie SENSOR_ATTR(in6_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 6), 579492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie SENSOR_ATTR(in7_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 7), 580492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie SENSOR_ATTR(in8_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 8), 581492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie SENSOR_ATTR(in9_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 9), 582492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie SENSOR_ATTR(in10_max_alarm, S_IRUGO, show_in_max_alarm, NULL, 10), 583492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie}; 584492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie 585941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie#define VIN_UNIT_ATTRS(X) \ 586941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie &in_input[X].dev_attr.attr, \ 587941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie &in_status[X].dev_attr.attr, \ 588941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie &in_min[X].dev_attr.attr, \ 589492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie &in_max[X].dev_attr.attr, \ 590492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie &in_min_alarm[X].dev_attr.attr, \ 591492e9657d1a790f44ab9b0e03fc72c1d8145f590Jim Cromie &in_max_alarm[X].dev_attr.attr 592941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie 593449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_vid(struct device *dev, struct device_attribute *attr, 594449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck char *buf) 59544646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromie{ 59644646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromie struct pc87360_data *data = pc87360_update_device(dev); 59744646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromie return sprintf(buf, "%u\n", vid_from_reg(data->vid, data->vrm)); 59844646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromie} 59944646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromiestatic DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); 60044646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromie 601449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_vrm(struct device *dev, struct device_attribute *attr, 602449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck char *buf) 60344646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromie{ 60490d6619a916062cb75a176aacb318d108758b4a5Jean Delvare struct pc87360_data *data = dev_get_drvdata(dev); 60544646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromie return sprintf(buf, "%u\n", data->vrm); 60644646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromie} 607449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t set_vrm(struct device *dev, struct device_attribute *attr, 608449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck const char *buf, size_t count) 60944646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromie{ 610f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare struct pc87360_data *data = dev_get_drvdata(dev); 611449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck unsigned long val; 612449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck int err; 613449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck 614449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck err = kstrtoul(buf, 10, &val); 615449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck if (err) 616449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck return err; 617449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck 618449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck data->vrm = val; 61944646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromie return count; 62044646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromie} 62144646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromiestatic DEVICE_ATTR(vrm, S_IRUGO | S_IWUSR, show_vrm, set_vrm); 62244646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromie 623449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_in_alarms(struct device *dev, 624449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck struct device_attribute *attr, char *buf) 62544646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromie{ 62644646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromie struct pc87360_data *data = pc87360_update_device(dev); 62744646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromie return sprintf(buf, "%u\n", data->in_alarms); 62844646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromie} 62944646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromiestatic DEVICE_ATTR(alarms_in, S_IRUGO, show_in_alarms, NULL); 63044646c19b41e40d81f5e4863466914e8ce060cc0Jim Cromie 631941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromiestatic struct attribute *pc8736x_vin_attr_array[] = { 632941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie VIN_UNIT_ATTRS(0), 633941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie VIN_UNIT_ATTRS(1), 634941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie VIN_UNIT_ATTRS(2), 635941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie VIN_UNIT_ATTRS(3), 636941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie VIN_UNIT_ATTRS(4), 637941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie VIN_UNIT_ATTRS(5), 638941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie VIN_UNIT_ATTRS(6), 639941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie VIN_UNIT_ATTRS(7), 640941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie VIN_UNIT_ATTRS(8), 641941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie VIN_UNIT_ATTRS(9), 642941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie VIN_UNIT_ATTRS(10), 643941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie &dev_attr_cpu0_vid.attr, 644941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie &dev_attr_vrm.attr, 645941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie &dev_attr_alarms_in.attr, 646941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie NULL 647941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie}; 648941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromiestatic const struct attribute_group pc8736x_vin_group = { 649941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie .attrs = pc8736x_vin_attr_array, 650941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie}; 651941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie 652449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_therm_input(struct device *dev, 653449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck struct device_attribute *devattr, char *buf) 654f0986bd8f390392948db85dac526fb238752372bJim Cromie{ 655f0986bd8f390392948db85dac526fb238752372bJim Cromie struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 656f0986bd8f390392948db85dac526fb238752372bJim Cromie struct pc87360_data *data = pc87360_update_device(dev); 657694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie return sprintf(buf, "%u\n", IN_FROM_REG(data->in[attr->index], 658f0986bd8f390392948db85dac526fb238752372bJim Cromie data->in_vref)); 659f0986bd8f390392948db85dac526fb238752372bJim Cromie} 660449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_therm_min(struct device *dev, 661449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck struct device_attribute *devattr, char *buf) 662f0986bd8f390392948db85dac526fb238752372bJim Cromie{ 663f0986bd8f390392948db85dac526fb238752372bJim Cromie struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 664f0986bd8f390392948db85dac526fb238752372bJim Cromie struct pc87360_data *data = pc87360_update_device(dev); 665694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie return sprintf(buf, "%u\n", IN_FROM_REG(data->in_min[attr->index], 666f0986bd8f390392948db85dac526fb238752372bJim Cromie data->in_vref)); 667f0986bd8f390392948db85dac526fb238752372bJim Cromie} 668449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_therm_max(struct device *dev, 669449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck struct device_attribute *devattr, char *buf) 670f0986bd8f390392948db85dac526fb238752372bJim Cromie{ 671f0986bd8f390392948db85dac526fb238752372bJim Cromie struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 672f0986bd8f390392948db85dac526fb238752372bJim Cromie struct pc87360_data *data = pc87360_update_device(dev); 673694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie return sprintf(buf, "%u\n", IN_FROM_REG(data->in_max[attr->index], 674f0986bd8f390392948db85dac526fb238752372bJim Cromie data->in_vref)); 675f0986bd8f390392948db85dac526fb238752372bJim Cromie} 676449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_therm_crit(struct device *dev, 677449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck struct device_attribute *devattr, char *buf) 678f0986bd8f390392948db85dac526fb238752372bJim Cromie{ 679f0986bd8f390392948db85dac526fb238752372bJim Cromie struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 680f0986bd8f390392948db85dac526fb238752372bJim Cromie struct pc87360_data *data = pc87360_update_device(dev); 681694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie return sprintf(buf, "%u\n", IN_FROM_REG(data->in_crit[attr->index-11], 682f0986bd8f390392948db85dac526fb238752372bJim Cromie data->in_vref)); 683f0986bd8f390392948db85dac526fb238752372bJim Cromie} 684449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_therm_status(struct device *dev, 685449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck struct device_attribute *devattr, char *buf) 686f0986bd8f390392948db85dac526fb238752372bJim Cromie{ 687f0986bd8f390392948db85dac526fb238752372bJim Cromie struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 688f0986bd8f390392948db85dac526fb238752372bJim Cromie struct pc87360_data *data = pc87360_update_device(dev); 689694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie return sprintf(buf, "%u\n", data->in_status[attr->index]); 690f0986bd8f390392948db85dac526fb238752372bJim Cromie} 691449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck 692449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t set_therm_min(struct device *dev, 693449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck struct device_attribute *devattr, 694449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck const char *buf, size_t count) 695f0986bd8f390392948db85dac526fb238752372bJim Cromie{ 696f0986bd8f390392948db85dac526fb238752372bJim Cromie struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 697f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare struct pc87360_data *data = dev_get_drvdata(dev); 698449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck long val; 699449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck int err; 700449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck 701449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck err = kstrtol(buf, 10, &val); 702449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck if (err) 703449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck return err; 704f0986bd8f390392948db85dac526fb238752372bJim Cromie 7059a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_lock(&data->update_lock); 706694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie data->in_min[attr->index] = IN_TO_REG(val, data->in_vref); 707694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_TEMP_MIN, 708694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie data->in_min[attr->index]); 7099a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_unlock(&data->update_lock); 710f0986bd8f390392948db85dac526fb238752372bJim Cromie return count; 711f0986bd8f390392948db85dac526fb238752372bJim Cromie} 712449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck 713449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t set_therm_max(struct device *dev, 714449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck struct device_attribute *devattr, 715449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck const char *buf, size_t count) 716f0986bd8f390392948db85dac526fb238752372bJim Cromie{ 717f0986bd8f390392948db85dac526fb238752372bJim Cromie struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 718f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare struct pc87360_data *data = dev_get_drvdata(dev); 719449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck long val; 720449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck int err; 721449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck 722449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck err = kstrtol(buf, 10, &val); 723449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck if (err) 724449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck return err; 725f0986bd8f390392948db85dac526fb238752372bJim Cromie 7269a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_lock(&data->update_lock); 727694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie data->in_max[attr->index] = IN_TO_REG(val, data->in_vref); 728694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_TEMP_MAX, 729694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie data->in_max[attr->index]); 7309a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_unlock(&data->update_lock); 731f0986bd8f390392948db85dac526fb238752372bJim Cromie return count; 732f0986bd8f390392948db85dac526fb238752372bJim Cromie} 733449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t set_therm_crit(struct device *dev, 734449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck struct device_attribute *devattr, 735449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck const char *buf, size_t count) 736f0986bd8f390392948db85dac526fb238752372bJim Cromie{ 737f0986bd8f390392948db85dac526fb238752372bJim Cromie struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 738f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare struct pc87360_data *data = dev_get_drvdata(dev); 739449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck long val; 740449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck int err; 741449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck 742449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck err = kstrtol(buf, 10, &val); 743449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck if (err) 744449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck return err; 745f0986bd8f390392948db85dac526fb238752372bJim Cromie 7469a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_lock(&data->update_lock); 747694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie data->in_crit[attr->index-11] = IN_TO_REG(val, data->in_vref); 748694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie pc87360_write_value(data, LD_IN, attr->index, PC87365_REG_TEMP_CRIT, 749694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie data->in_crit[attr->index-11]); 7509a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_unlock(&data->update_lock); 751f0986bd8f390392948db85dac526fb238752372bJim Cromie return count; 752f0986bd8f390392948db85dac526fb238752372bJim Cromie} 753f0986bd8f390392948db85dac526fb238752372bJim Cromie 7543af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck/* 7553af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * the +11 term below reflects the fact that VLM units 11,12,13 are 7563af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * used in the chip to measure voltage across the thermistors 7573af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck */ 758dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute therm_input[] = { 759449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck SENSOR_ATTR(temp4_input, S_IRUGO, show_therm_input, NULL, 0 + 11), 760449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck SENSOR_ATTR(temp5_input, S_IRUGO, show_therm_input, NULL, 1 + 11), 761449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck SENSOR_ATTR(temp6_input, S_IRUGO, show_therm_input, NULL, 2 + 11), 762dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie}; 763dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute therm_status[] = { 764449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck SENSOR_ATTR(temp4_status, S_IRUGO, show_therm_status, NULL, 0 + 11), 765449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck SENSOR_ATTR(temp5_status, S_IRUGO, show_therm_status, NULL, 1 + 11), 766449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck SENSOR_ATTR(temp6_status, S_IRUGO, show_therm_status, NULL, 2 + 11), 767dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie}; 768dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute therm_min[] = { 769dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(temp4_min, S_IRUGO | S_IWUSR, 770449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck show_therm_min, set_therm_min, 0 + 11), 771dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(temp5_min, S_IRUGO | S_IWUSR, 772449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck show_therm_min, set_therm_min, 1 + 11), 773dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(temp6_min, S_IRUGO | S_IWUSR, 774449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck show_therm_min, set_therm_min, 2 + 11), 775dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie}; 776dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute therm_max[] = { 777dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(temp4_max, S_IRUGO | S_IWUSR, 778449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck show_therm_max, set_therm_max, 0 + 11), 779dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(temp5_max, S_IRUGO | S_IWUSR, 780449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck show_therm_max, set_therm_max, 1 + 11), 781dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(temp6_max, S_IRUGO | S_IWUSR, 782449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck show_therm_max, set_therm_max, 2 + 11), 783dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie}; 784dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute therm_crit[] = { 785dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(temp4_crit, S_IRUGO | S_IWUSR, 786449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck show_therm_crit, set_therm_crit, 0 + 11), 787dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(temp5_crit, S_IRUGO | S_IWUSR, 788449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck show_therm_crit, set_therm_crit, 1 + 11), 789dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(temp6_crit, S_IRUGO | S_IWUSR, 790449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck show_therm_crit, set_therm_crit, 2 + 11), 791dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie}; 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7933af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck/* 7943af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * show_therm_min/max_alarm() reads data from the per-channel voltage 7953af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * status register (sec 11.5.12) 7963af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck */ 797865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie 798865c295360f61c2f3634fb1387b4468fdc8287daJim Cromiestatic ssize_t show_therm_min_alarm(struct device *dev, 799865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie struct device_attribute *devattr, char *buf) 800865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie{ 801865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie struct pc87360_data *data = pc87360_update_device(dev); 802865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie unsigned nr = to_sensor_dev_attr(devattr)->index; 803865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie 804865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie return sprintf(buf, "%u\n", !!(data->in_status[nr] & CHAN_ALM_MIN)); 805865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie} 806865c295360f61c2f3634fb1387b4468fdc8287daJim Cromiestatic ssize_t show_therm_max_alarm(struct device *dev, 807865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie struct device_attribute *devattr, char *buf) 808865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie{ 809865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie struct pc87360_data *data = pc87360_update_device(dev); 810865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie unsigned nr = to_sensor_dev_attr(devattr)->index; 811865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie 812865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie return sprintf(buf, "%u\n", !!(data->in_status[nr] & CHAN_ALM_MAX)); 813865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie} 814865c295360f61c2f3634fb1387b4468fdc8287daJim Cromiestatic ssize_t show_therm_crit_alarm(struct device *dev, 815865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie struct device_attribute *devattr, char *buf) 816865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie{ 817865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie struct pc87360_data *data = pc87360_update_device(dev); 818865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie unsigned nr = to_sensor_dev_attr(devattr)->index; 819865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie 820865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie return sprintf(buf, "%u\n", !!(data->in_status[nr] & TEMP_ALM_CRIT)); 821865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie} 822865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie 823865c295360f61c2f3634fb1387b4468fdc8287daJim Cromiestatic struct sensor_device_attribute therm_min_alarm[] = { 824865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie SENSOR_ATTR(temp4_min_alarm, S_IRUGO, 825449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck show_therm_min_alarm, NULL, 0 + 11), 826865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie SENSOR_ATTR(temp5_min_alarm, S_IRUGO, 827449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck show_therm_min_alarm, NULL, 1 + 11), 828865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie SENSOR_ATTR(temp6_min_alarm, S_IRUGO, 829449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck show_therm_min_alarm, NULL, 2 + 11), 830865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie}; 831865c295360f61c2f3634fb1387b4468fdc8287daJim Cromiestatic struct sensor_device_attribute therm_max_alarm[] = { 832865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie SENSOR_ATTR(temp4_max_alarm, S_IRUGO, 833449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck show_therm_max_alarm, NULL, 0 + 11), 834865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie SENSOR_ATTR(temp5_max_alarm, S_IRUGO, 835449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck show_therm_max_alarm, NULL, 1 + 11), 836865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie SENSOR_ATTR(temp6_max_alarm, S_IRUGO, 837449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck show_therm_max_alarm, NULL, 2 + 11), 838865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie}; 839865c295360f61c2f3634fb1387b4468fdc8287daJim Cromiestatic struct sensor_device_attribute therm_crit_alarm[] = { 840865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie SENSOR_ATTR(temp4_crit_alarm, S_IRUGO, 841449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck show_therm_crit_alarm, NULL, 0 + 11), 842865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie SENSOR_ATTR(temp5_crit_alarm, S_IRUGO, 843449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck show_therm_crit_alarm, NULL, 1 + 11), 844865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie SENSOR_ATTR(temp6_crit_alarm, S_IRUGO, 845449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck show_therm_crit_alarm, NULL, 2 + 11), 846865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie}; 847865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie 848941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie#define THERM_UNIT_ATTRS(X) \ 849941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie &therm_input[X].dev_attr.attr, \ 850941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie &therm_status[X].dev_attr.attr, \ 851941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie &therm_min[X].dev_attr.attr, \ 852941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie &therm_max[X].dev_attr.attr, \ 853865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie &therm_crit[X].dev_attr.attr, \ 854865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie &therm_min_alarm[X].dev_attr.attr, \ 855865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie &therm_max_alarm[X].dev_attr.attr, \ 856865c295360f61c2f3634fb1387b4468fdc8287daJim Cromie &therm_crit_alarm[X].dev_attr.attr 857941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie 858449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic struct attribute *pc8736x_therm_attr_array[] = { 859941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie THERM_UNIT_ATTRS(0), 860941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie THERM_UNIT_ATTRS(1), 861941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie THERM_UNIT_ATTRS(2), 862941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie NULL 863941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie}; 864941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromiestatic const struct attribute_group pc8736x_therm_group = { 865941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie .attrs = pc8736x_therm_attr_array, 866941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie}; 867941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie 868449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_temp_input(struct device *dev, 869449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck struct device_attribute *devattr, char *buf) 870f0986bd8f390392948db85dac526fb238752372bJim Cromie{ 871f0986bd8f390392948db85dac526fb238752372bJim Cromie struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 872f0986bd8f390392948db85dac526fb238752372bJim Cromie struct pc87360_data *data = pc87360_update_device(dev); 873694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[attr->index])); 874f0986bd8f390392948db85dac526fb238752372bJim Cromie} 875449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck 876449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_temp_min(struct device *dev, 877449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck struct device_attribute *devattr, char *buf) 878f0986bd8f390392948db85dac526fb238752372bJim Cromie{ 879f0986bd8f390392948db85dac526fb238752372bJim Cromie struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 880f0986bd8f390392948db85dac526fb238752372bJim Cromie struct pc87360_data *data = pc87360_update_device(dev); 881694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_min[attr->index])); 882f0986bd8f390392948db85dac526fb238752372bJim Cromie} 883449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck 884449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_temp_max(struct device *dev, 885449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck struct device_attribute *devattr, char *buf) 886f0986bd8f390392948db85dac526fb238752372bJim Cromie{ 887f0986bd8f390392948db85dac526fb238752372bJim Cromie struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 888f0986bd8f390392948db85dac526fb238752372bJim Cromie struct pc87360_data *data = pc87360_update_device(dev); 889694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_max[attr->index])); 890f0986bd8f390392948db85dac526fb238752372bJim Cromie} 891449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck 892449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_temp_crit(struct device *dev, 893449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck struct device_attribute *devattr, char *buf) 894f0986bd8f390392948db85dac526fb238752372bJim Cromie{ 895f0986bd8f390392948db85dac526fb238752372bJim Cromie struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 896f0986bd8f390392948db85dac526fb238752372bJim Cromie struct pc87360_data *data = pc87360_update_device(dev); 897449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck return sprintf(buf, "%d\n", 898449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck TEMP_FROM_REG(data->temp_crit[attr->index])); 899f0986bd8f390392948db85dac526fb238752372bJim Cromie} 900449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck 901449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_temp_status(struct device *dev, 902449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck struct device_attribute *devattr, char *buf) 903f0986bd8f390392948db85dac526fb238752372bJim Cromie{ 904f0986bd8f390392948db85dac526fb238752372bJim Cromie struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 905f0986bd8f390392948db85dac526fb238752372bJim Cromie struct pc87360_data *data = pc87360_update_device(dev); 906694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie return sprintf(buf, "%d\n", data->temp_status[attr->index]); 907f0986bd8f390392948db85dac526fb238752372bJim Cromie} 908449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck 909449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t set_temp_min(struct device *dev, 910449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck struct device_attribute *devattr, 911449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck const char *buf, size_t count) 912f0986bd8f390392948db85dac526fb238752372bJim Cromie{ 913f0986bd8f390392948db85dac526fb238752372bJim Cromie struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 914f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare struct pc87360_data *data = dev_get_drvdata(dev); 915449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck long val; 916449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck int err; 917449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck 918449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck err = kstrtol(buf, 10, &val); 919449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck if (err) 920449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck return err; 921f0986bd8f390392948db85dac526fb238752372bJim Cromie 9229a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_lock(&data->update_lock); 923694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie data->temp_min[attr->index] = TEMP_TO_REG(val); 924694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie pc87360_write_value(data, LD_TEMP, attr->index, PC87365_REG_TEMP_MIN, 925694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie data->temp_min[attr->index]); 9269a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_unlock(&data->update_lock); 927f0986bd8f390392948db85dac526fb238752372bJim Cromie return count; 928f0986bd8f390392948db85dac526fb238752372bJim Cromie} 929449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck 930449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t set_temp_max(struct device *dev, 931449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck struct device_attribute *devattr, 932449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck const char *buf, size_t count) 933f0986bd8f390392948db85dac526fb238752372bJim Cromie{ 934f0986bd8f390392948db85dac526fb238752372bJim Cromie struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 935f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare struct pc87360_data *data = dev_get_drvdata(dev); 936449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck long val; 937449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck int err; 938449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck 939449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck err = kstrtol(buf, 10, &val); 940449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck if (err) 941449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck return err; 942f0986bd8f390392948db85dac526fb238752372bJim Cromie 9439a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_lock(&data->update_lock); 944694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie data->temp_max[attr->index] = TEMP_TO_REG(val); 945694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie pc87360_write_value(data, LD_TEMP, attr->index, PC87365_REG_TEMP_MAX, 946694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie data->temp_max[attr->index]); 9479a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_unlock(&data->update_lock); 948f0986bd8f390392948db85dac526fb238752372bJim Cromie return count; 949f0986bd8f390392948db85dac526fb238752372bJim Cromie} 950449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck 951449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t set_temp_crit(struct device *dev, 952449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck struct device_attribute *devattr, const char *buf, 953449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck size_t count) 954f0986bd8f390392948db85dac526fb238752372bJim Cromie{ 955f0986bd8f390392948db85dac526fb238752372bJim Cromie struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 956f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare struct pc87360_data *data = dev_get_drvdata(dev); 957449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck long val; 958449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck int err; 959449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck 960449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck err = kstrtol(buf, 10, &val); 961449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck if (err) 962449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck return err; 963f0986bd8f390392948db85dac526fb238752372bJim Cromie 9649a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_lock(&data->update_lock); 965694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie data->temp_crit[attr->index] = TEMP_TO_REG(val); 966694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie pc87360_write_value(data, LD_TEMP, attr->index, PC87365_REG_TEMP_CRIT, 967694fa056a60828ef54a5db958468cc600c3b3622Jim Cromie data->temp_crit[attr->index]); 9689a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_unlock(&data->update_lock); 969f0986bd8f390392948db85dac526fb238752372bJim Cromie return count; 970f0986bd8f390392948db85dac526fb238752372bJim Cromie} 971f0986bd8f390392948db85dac526fb238752372bJim Cromie 972dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute temp_input[] = { 973dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL, 0), 974dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(temp2_input, S_IRUGO, show_temp_input, NULL, 1), 975dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(temp3_input, S_IRUGO, show_temp_input, NULL, 2), 976dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie}; 977dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute temp_status[] = { 978dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(temp1_status, S_IRUGO, show_temp_status, NULL, 0), 979dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(temp2_status, S_IRUGO, show_temp_status, NULL, 1), 980dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(temp3_status, S_IRUGO, show_temp_status, NULL, 2), 981dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie}; 982dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute temp_min[] = { 983dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(temp1_min, S_IRUGO | S_IWUSR, 984dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie show_temp_min, set_temp_min, 0), 985dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(temp2_min, S_IRUGO | S_IWUSR, 986dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie show_temp_min, set_temp_min, 1), 987dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(temp3_min, S_IRUGO | S_IWUSR, 988dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie show_temp_min, set_temp_min, 2), 989dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie}; 990dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute temp_max[] = { 991dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(temp1_max, S_IRUGO | S_IWUSR, 992dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie show_temp_max, set_temp_max, 0), 993dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(temp2_max, S_IRUGO | S_IWUSR, 994dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie show_temp_max, set_temp_max, 1), 995dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(temp3_max, S_IRUGO | S_IWUSR, 996dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie show_temp_max, set_temp_max, 2), 997dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie}; 998dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromiestatic struct sensor_device_attribute temp_crit[] = { 999dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(temp1_crit, S_IRUGO | S_IWUSR, 1000dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie show_temp_crit, set_temp_crit, 0), 1001dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(temp2_crit, S_IRUGO | S_IWUSR, 1002dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie show_temp_crit, set_temp_crit, 1), 1003dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie SENSOR_ATTR(temp3_crit, S_IRUGO | S_IWUSR, 1004dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie show_temp_crit, set_temp_crit, 2), 1005dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie}; 10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1007449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic ssize_t show_temp_alarms(struct device *dev, 1008449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck struct device_attribute *attr, char *buf) 10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pc87360_data *data = pc87360_update_device(dev); 10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf(buf, "%u\n", data->temp_alarms); 10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1013449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck 10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(alarms_temp, S_IRUGO, show_temp_alarms, NULL); 10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10163af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck/* 10173af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * show_temp_min/max_alarm() reads data from the per-channel status 10183af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * register (sec 12.3.7), not the temp event status registers (sec 10193af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * 12.3.2) that show_temp_alarm() reads (via data->temp_alarms) 10203af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck */ 1021b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie 1022b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromiestatic ssize_t show_temp_min_alarm(struct device *dev, 1023b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie struct device_attribute *devattr, char *buf) 1024b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie{ 1025b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie struct pc87360_data *data = pc87360_update_device(dev); 1026b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie unsigned nr = to_sensor_dev_attr(devattr)->index; 1027b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie 1028b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie return sprintf(buf, "%u\n", !!(data->temp_status[nr] & CHAN_ALM_MIN)); 1029b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie} 1030449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck 1031b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromiestatic ssize_t show_temp_max_alarm(struct device *dev, 1032b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie struct device_attribute *devattr, char *buf) 1033b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie{ 1034b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie struct pc87360_data *data = pc87360_update_device(dev); 1035b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie unsigned nr = to_sensor_dev_attr(devattr)->index; 1036b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie 1037b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie return sprintf(buf, "%u\n", !!(data->temp_status[nr] & CHAN_ALM_MAX)); 1038b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie} 1039449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck 1040b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromiestatic ssize_t show_temp_crit_alarm(struct device *dev, 1041b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie struct device_attribute *devattr, char *buf) 1042b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie{ 1043b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie struct pc87360_data *data = pc87360_update_device(dev); 1044b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie unsigned nr = to_sensor_dev_attr(devattr)->index; 1045b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie 1046b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie return sprintf(buf, "%u\n", !!(data->temp_status[nr] & TEMP_ALM_CRIT)); 1047b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie} 1048b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie 1049b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromiestatic struct sensor_device_attribute temp_min_alarm[] = { 1050b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie SENSOR_ATTR(temp1_min_alarm, S_IRUGO, show_temp_min_alarm, NULL, 0), 1051b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie SENSOR_ATTR(temp2_min_alarm, S_IRUGO, show_temp_min_alarm, NULL, 1), 1052b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie SENSOR_ATTR(temp3_min_alarm, S_IRUGO, show_temp_min_alarm, NULL, 2), 1053b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie}; 1054449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck 1055b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromiestatic struct sensor_device_attribute temp_max_alarm[] = { 1056b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie SENSOR_ATTR(temp1_max_alarm, S_IRUGO, show_temp_max_alarm, NULL, 0), 1057b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie SENSOR_ATTR(temp2_max_alarm, S_IRUGO, show_temp_max_alarm, NULL, 1), 1058b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie SENSOR_ATTR(temp3_max_alarm, S_IRUGO, show_temp_max_alarm, NULL, 2), 1059b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie}; 1060449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck 1061b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromiestatic struct sensor_device_attribute temp_crit_alarm[] = { 1062b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie SENSOR_ATTR(temp1_crit_alarm, S_IRUGO, show_temp_crit_alarm, NULL, 0), 1063b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie SENSOR_ATTR(temp2_crit_alarm, S_IRUGO, show_temp_crit_alarm, NULL, 1), 1064b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie SENSOR_ATTR(temp3_crit_alarm, S_IRUGO, show_temp_crit_alarm, NULL, 2), 1065b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie}; 1066b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie 1067b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie#define TEMP_FAULT 0x40 /* open diode */ 1068b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromiestatic ssize_t show_temp_fault(struct device *dev, 1069b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie struct device_attribute *devattr, char *buf) 1070b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie{ 1071b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie struct pc87360_data *data = pc87360_update_device(dev); 1072b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie unsigned nr = to_sensor_dev_attr(devattr)->index; 1073b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie 1074b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie return sprintf(buf, "%u\n", !!(data->temp_status[nr] & TEMP_FAULT)); 1075b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie} 1076b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromiestatic struct sensor_device_attribute temp_fault[] = { 1077b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie SENSOR_ATTR(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0), 1078b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie SENSOR_ATTR(temp2_fault, S_IRUGO, show_temp_fault, NULL, 1), 1079b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie SENSOR_ATTR(temp3_fault, S_IRUGO, show_temp_fault, NULL, 2), 1080b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie}; 1081b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie 1082bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck#define TEMP_UNIT_ATTRS(X) \ 1083bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck{ &temp_input[X].dev_attr.attr, \ 1084bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck &temp_status[X].dev_attr.attr, \ 1085bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck &temp_min[X].dev_attr.attr, \ 1086bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck &temp_max[X].dev_attr.attr, \ 1087bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck &temp_crit[X].dev_attr.attr, \ 1088bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck &temp_min_alarm[X].dev_attr.attr, \ 1089bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck &temp_max_alarm[X].dev_attr.attr, \ 1090bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck &temp_crit_alarm[X].dev_attr.attr, \ 1091bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck &temp_fault[X].dev_attr.attr, \ 1092bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck NULL \ 1093bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck} 1094bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck 1095bce2778df9ea32146d59344c027001e270911f4bGuenter Roeckstatic struct attribute *pc8736x_temp_attr[][10] = { 1096941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie TEMP_UNIT_ATTRS(0), 1097941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie TEMP_UNIT_ATTRS(1), 1098bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck TEMP_UNIT_ATTRS(2) 1099941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie}; 1100449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck 1101bce2778df9ea32146d59344c027001e270911f4bGuenter Roeckstatic const struct attribute_group pc8736x_temp_attr_group[] = { 1102bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck { .attrs = pc8736x_temp_attr[0] }, 1103bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck { .attrs = pc8736x_temp_attr[1] }, 1104bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck { .attrs = pc8736x_temp_attr[2] } 1105941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie}; 1106941c5c05cf38da5e12d70edc5d0fec5c24bce8b6Jim Cromie 1107b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromiestatic ssize_t show_name(struct device *dev, 1108b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie struct device_attribute *devattr, char *buf) 1109f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare{ 1110f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare struct pc87360_data *data = dev_get_drvdata(dev); 1111f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare return sprintf(buf, "%s\n", data->name); 1112f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare} 1113449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck 1114f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvarestatic DEVICE_ATTR(name, S_IRUGO, show_name, NULL); 1115f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare 11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Device detection, registration and update 11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1120449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeckstatic int __init pc87360_find(int sioaddr, u8 *devid, 1121449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck unsigned short *addresses) 11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 val; 11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int nrdev; /* logical device count */ 11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* No superio_enter */ 11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Identify device */ 113067b671bceb4a8340a30929e9642620d99ed5ad76Jean Delvare val = force_id ? force_id : superio_inb(sioaddr, DEVID); 11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (val) { 11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0xE1: /* PC87360 */ 11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0xE8: /* PC87363 */ 11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0xE4: /* PC87364 */ 11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nrdev = 1; 11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0xE5: /* PC87365 */ 11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0xE9: /* PC87366 */ 11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nrdev = 3; 11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds superio_exit(sioaddr); 11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Remember the device id */ 11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *devid = val; 11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < nrdev; i++) { 11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* select logical device */ 11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds superio_outb(sioaddr, DEV, logdev[i]); 11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = superio_inb(sioaddr, ACT); 11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(val & 0x01)) { 11549e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches pr_info("Device 0x%02x not activated\n", logdev[i]); 11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds val = (superio_inb(sioaddr, BASE) << 8) 11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | superio_inb(sioaddr, BASE + 1); 11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!val) { 11619e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches pr_info("Base address not set for device 0x%02x\n", 11629e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches logdev[i]); 11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11662d8672c5a6ba0d3f1d8d3ad61ef67868941364f0Jean Delvare addresses[i] = val; 11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1168449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck if (i == 0) { /* Fans */ 11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds confreg[0] = superio_inb(sioaddr, 0xF0); 11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds confreg[1] = superio_inb(sioaddr, 0xF1); 11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11729e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches pr_debug("Fan %d: mon=%d ctrl=%d inv=%d\n", 1, 11739e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches (confreg[0] >> 2) & 1, (confreg[0] >> 3) & 1, 11749e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches (confreg[0] >> 4) & 1); 11759e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches pr_debug("Fan %d: mon=%d ctrl=%d inv=%d\n", 2, 11769e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches (confreg[0] >> 5) & 1, (confreg[0] >> 6) & 1, 11779e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches (confreg[0] >> 7) & 1); 11789e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches pr_debug("Fan %d: mon=%d ctrl=%d inv=%d\n", 3, 11799e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches confreg[1] & 1, (confreg[1] >> 1) & 1, 11809e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches (confreg[1] >> 2) & 1); 1181449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck } else if (i == 1) { /* Voltages */ 11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Are we using thermistors? */ 11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (*devid == 0xE9) { /* PC87366 */ 11843af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck /* 11853af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * These registers are not logical-device 11863af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * specific, just that we won't need them if 11873af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * we don't use the VLM device 11883af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck */ 11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds confreg[2] = superio_inb(sioaddr, 0x2B); 11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds confreg[3] = superio_inb(sioaddr, 0x25); 11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (confreg[2] & 0x40) { 11939e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches pr_info("Using thermistors for " 11949e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches "temperature monitoring\n"); 11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (confreg[3] & 0xE0) { 11979e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches pr_info("VID inputs routed (mode %u)\n", 11989e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches confreg[3] >> 5); 11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds superio_exit(sioaddr); 12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1208bce2778df9ea32146d59344c027001e270911f4bGuenter Roeckstatic void pc87360_remove_files(struct device *dev) 1209bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck{ 1210bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck int i; 1211bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck 1212bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck device_remove_file(dev, &dev_attr_name); 1213bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck device_remove_file(dev, &dev_attr_alarms_temp); 1214bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck for (i = 0; i < ARRAY_SIZE(pc8736x_temp_attr_group); i++) 1215bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck sysfs_remove_group(&dev->kobj, &pc8736x_temp_attr_group[i]); 1216bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck for (i = 0; i < ARRAY_SIZE(pc8736x_fan_attr_group); i++) { 1217bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck sysfs_remove_group(&pdev->dev.kobj, &pc8736x_fan_attr_group[i]); 1218bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck device_remove_file(dev, &pwm[i].dev_attr); 1219bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck } 1220bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck sysfs_remove_group(&dev->kobj, &pc8736x_therm_group); 1221bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck sysfs_remove_group(&dev->kobj, &pc8736x_vin_group); 1222bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck} 1223bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck 1224f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvarestatic int __devinit pc87360_probe(struct platform_device *pdev) 12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct pc87360_data *data; 12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err = 0; 12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const char *name = "pc87360"; 12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int use_thermistors = 0; 1231f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare struct device *dev = &pdev->dev; 12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1233449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck data = kzalloc(sizeof(struct pc87360_data), GFP_KERNEL); 1234449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck if (!data) 12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fannr = 2; 12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->innr = 0; 12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->tempnr = 0; 12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (devid) { 12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0xe8: 12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds name = "pc87363"; 12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0xe4: 12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds name = "pc87364"; 12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fannr = 3; 12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0xe5: 12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds name = "pc87365"; 12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fannr = extra_isa[0] ? 3 : 0; 12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->innr = extra_isa[1] ? 11 : 0; 12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->tempnr = extra_isa[2] ? 2 : 0; 12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0xe9: 12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds name = "pc87366"; 12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fannr = extra_isa[0] ? 3 : 0; 12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->innr = extra_isa[1] ? 14 : 0; 12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->tempnr = extra_isa[2] ? 3 : 0; 12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1263f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare data->name = name; 12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->valid = 0; 1265f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare mutex_init(&data->lock); 12669a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_init(&data->update_lock); 1267f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare platform_set_drvdata(pdev, data); 12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12692a32ec2500514109754e07721d9d5d431a706a31Jim Cromie for (i = 0; i < LDNI_MAX; i++) { 1270449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck data->address[i] = extra_isa[i]; 1271449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck if (data->address[i] 12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && !request_region(extra_isa[i], PC87360_EXTENT, 1273449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck pc87360_driver.driver.name)) { 1274f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare dev_err(dev, "Region 0x%x-0x%x already " 12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "in use!\n", extra_isa[i], 12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds extra_isa[i]+PC87360_EXTENT-1); 12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i--; i >= 0; i--) 12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(extra_isa[i], PC87360_EXTENT); 12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err = -EBUSY; 12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto ERROR1; 12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Retrieve the fans configuration from Super-I/O space */ 12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->fannr) 12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fan_conf = confreg[0] | (confreg[1] << 8); 12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12883af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck /* 12893af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * Use the correct reference voltage 12903af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * Unless both the VLM and the TMS logical devices agree to 12913af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * use an external Vref, the internal one is used. 12923af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck */ 12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->innr) { 12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = pc87360_read_value(data, LD_IN, NO_BANK, 12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PC87365_REG_IN_CONFIG); 12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->tempnr) { 12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i &= pc87360_read_value(data, LD_TEMP, NO_BANK, 12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PC87365_REG_TEMP_CONFIG); 12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->in_vref = (i&0x02) ? 3025 : 2966; 1301f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare dev_dbg(dev, "Using %s reference voltage\n", 13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (i&0x02) ? "external" : "internal"); 13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->vid_conf = confreg[3]; 13053d7f9a8697ffe76e9edaf6b1751f2a2db660e4d5Jim Cromie data->vrm = vid_which_vrm(); 13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Fan clock dividers may be needed before any data is read */ 13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < data->fannr; i++) { 13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (FAN_CONFIG_MONITOR(data->fan_conf, i)) 13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fan_status[i] = pc87360_read_value(data, 13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LD_FAN, NO_BANK, 13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PC87360_REG_FAN_STATUS(i)); 13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (init > 0) { 13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (devid == 0xe9 && data->address[1]) /* PC87366 */ 13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds use_thermistors = confreg[2] & 0x40; 13191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1320f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare pc87360_init_device(pdev, use_thermistors); 13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1323f3722d5b6a474e31237d23980e9bd38facfda6f4Jim Cromie /* Register all-or-nothing sysfs groups */ 1324f3722d5b6a474e31237d23980e9bd38facfda6f4Jim Cromie 1325449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck if (data->innr) { 1326449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck err = sysfs_create_group(&dev->kobj, &pc8736x_vin_group); 1327449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck if (err) 1328449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck goto ERROR3; 1329449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck } 1330943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman 1331449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck if (data->innr == 14) { 1332449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck err = sysfs_create_group(&dev->kobj, &pc8736x_therm_group); 1333449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck if (err) 1334449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck goto ERROR3; 1335449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck } 1336f3722d5b6a474e31237d23980e9bd38facfda6f4Jim Cromie 1337f3722d5b6a474e31237d23980e9bd38facfda6f4Jim Cromie /* create device attr-files for varying sysfs groups */ 13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->tempnr) { 1340dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie for (i = 0; i < data->tempnr; i++) { 1341bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck err = sysfs_create_group(&dev->kobj, 1342bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck &pc8736x_temp_attr_group[i]); 1343bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck if (err) 1344f3722d5b6a474e31237d23980e9bd38facfda6f4Jim Cromie goto ERROR3; 13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1346449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck err = device_create_file(dev, &dev_attr_alarms_temp); 1347449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck if (err) 1348f3722d5b6a474e31237d23980e9bd38facfda6f4Jim Cromie goto ERROR3; 13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1351dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie for (i = 0; i < data->fannr; i++) { 1352bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck if (FAN_CONFIG_MONITOR(data->fan_conf, i)) { 1353bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck err = sysfs_create_group(&dev->kobj, 1354bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck &pc8736x_fan_attr_group[i]); 1355bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck if (err) 1356bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck goto ERROR3; 1357bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck } 1358449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck if (FAN_CONFIG_CONTROL(data->fan_conf, i)) { 1359449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck err = device_create_file(dev, &pwm[i].dev_attr); 1360449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck if (err) 1361449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck goto ERROR3; 1362449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck } 13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1365449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck err = device_create_file(dev, &dev_attr_name); 1366449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck if (err) 1367f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare goto ERROR3; 1368f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare 13691beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones data->hwmon_dev = hwmon_device_register(dev); 13701beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones if (IS_ERR(data->hwmon_dev)) { 13711beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones err = PTR_ERR(data->hwmon_dev); 1372f3722d5b6a474e31237d23980e9bd38facfda6f4Jim Cromie goto ERROR3; 1373f3722d5b6a474e31237d23980e9bd38facfda6f4Jim Cromie } 13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1376943b0830cebe4711354945ed3cb44e84152aaca0Mark M. HoffmanERROR3: 1377bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck pc87360_remove_files(dev); 13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 3; i++) { 1379449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck if (data->address[i]) 13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(data->address[i], PC87360_EXTENT); 13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsERROR1: 13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(data); 13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1387f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvarestatic int __devexit pc87360_remove(struct platform_device *pdev) 13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1389f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare struct pc87360_data *data = platform_get_drvdata(pdev); 13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13921beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones hwmon_device_unregister(data->hwmon_dev); 1393bce2778df9ea32146d59344c027001e270911f4bGuenter Roeck pc87360_remove_files(&pdev->dev); 13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 3; i++) { 1395449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck if (data->address[i]) 13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(data->address[i], PC87360_EXTENT); 13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(data); 13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14033af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck/* 14043af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * ldi is the logical device index 14053af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * bank is for voltages and temperatures only 14063af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck */ 14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank, 14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 reg) 14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int res; 14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14129a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_lock(&(data->lock)); 14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bank != NO_BANK) 14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(bank, data->address[ldi] + PC87365_REG_BANK); 14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds res = inb_p(data->address[ldi] + reg); 14169a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_unlock(&(data->lock)); 14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return res; 14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank, 14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 reg, u8 value) 14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14249a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_lock(&(data->lock)); 14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bank != NO_BANK) 14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(bank, data->address[ldi] + PC87365_REG_BANK); 14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb_p(value, data->address[ldi] + reg); 14289a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_unlock(&(data->lock)); 14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 143128f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie/* (temp & vin) channel conversion status register flags (pdf sec.11.5.12) */ 143228f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie#define CHAN_CNVRTD 0x80 /* new data ready */ 143328f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie#define CHAN_ENA 0x01 /* enabled channel (temp or vin) */ 143428f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie#define CHAN_ALM_ENA 0x10 /* propagate to alarms-reg ?? (chk val!) */ 143528f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie#define CHAN_READY (CHAN_ENA|CHAN_CNVRTD) /* sample ready mask */ 143628f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie 1437b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie#define TEMP_OTS_OE 0x20 /* OTS Output Enable */ 1438b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie#define VIN_RW1C_MASK (CHAN_READY|CHAN_ALM_MAX|CHAN_ALM_MIN) /* 0x87 */ 1439b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie#define TEMP_RW1C_MASK (VIN_RW1C_MASK|TEMP_ALM_CRIT|TEMP_FAULT) /* 0xCF */ 1440b267e8cdc638dfa53360d532aa56afa0ec12e6a5Jim Cromie 1441f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvarestatic void pc87360_init_device(struct platform_device *pdev, 1442f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare int use_thermistors) 14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1444f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare struct pc87360_data *data = platform_get_drvdata(pdev); 14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, nr; 14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const u8 init_in[14] = { 2, 2, 2, 2, 2, 2, 2, 1, 1, 3, 1, 2, 2, 2 }; 14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds const u8 init_temp[3] = { 2, 2, 1 }; 14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 reg; 14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (init >= 2 && data->innr) { 14511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg = pc87360_read_value(data, LD_IN, NO_BANK, 14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PC87365_REG_IN_CONVRATE); 1453f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare dev_info(&pdev->dev, "VLM conversion set to " 14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "1s period, 160us delay\n"); 14551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pc87360_write_value(data, LD_IN, NO_BANK, 14561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PC87365_REG_IN_CONVRATE, 14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (reg & 0xC0) | 0x11); 14581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nr = data->innr < 11 ? data->innr : 11; 1461dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie for (i = 0; i < nr; i++) { 14628ca136741e15e8546e787ae92a7f4aeca84be494Jim Cromie reg = pc87360_read_value(data, LD_IN, i, 14638ca136741e15e8546e787ae92a7f4aeca84be494Jim Cromie PC87365_REG_IN_STATUS); 14648ca136741e15e8546e787ae92a7f4aeca84be494Jim Cromie dev_dbg(&pdev->dev, "bios in%d status:0x%02x\n", i, reg); 14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (init >= init_in[i]) { 14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Forcibly enable voltage channel */ 146728f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie if (!(reg & CHAN_ENA)) { 1468f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare dev_dbg(&pdev->dev, "Forcibly " 14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "enabling in%d\n", i); 14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pc87360_write_value(data, LD_IN, i, 14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PC87365_REG_IN_STATUS, 14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (reg & 0x68) | 0x87); 14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14773af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck /* 14783af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * We can't blindly trust the Super-I/O space configuration bit, 14793af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * most BIOS won't set it properly 14803af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck */ 14818ca136741e15e8546e787ae92a7f4aeca84be494Jim Cromie dev_dbg(&pdev->dev, "bios thermistors:%d\n", use_thermistors); 1482dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie for (i = 11; i < data->innr; i++) { 14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg = pc87360_read_value(data, LD_IN, i, 14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PC87365_REG_TEMP_STATUS); 148528f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie use_thermistors = use_thermistors || (reg & CHAN_ENA); 14868ca136741e15e8546e787ae92a7f4aeca84be494Jim Cromie /* thermistors are temp[4-6], measured on vin[11-14] */ 14878ca136741e15e8546e787ae92a7f4aeca84be494Jim Cromie dev_dbg(&pdev->dev, "bios temp%d_status:0x%02x\n", i-7, reg); 14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14898ca136741e15e8546e787ae92a7f4aeca84be494Jim Cromie dev_dbg(&pdev->dev, "using thermistors:%d\n", use_thermistors); 14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = use_thermistors ? 2 : 0; 1492dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie for (; i < data->tempnr; i++) { 14938ca136741e15e8546e787ae92a7f4aeca84be494Jim Cromie reg = pc87360_read_value(data, LD_TEMP, i, 14948ca136741e15e8546e787ae92a7f4aeca84be494Jim Cromie PC87365_REG_TEMP_STATUS); 1495449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck dev_dbg(&pdev->dev, "bios temp%d_status:0x%02x\n", i + 1, reg); 14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (init >= init_temp[i]) { 14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Forcibly enable temperature channel */ 149828f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie if (!(reg & CHAN_ENA)) { 1499449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck dev_dbg(&pdev->dev, 1500449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck "Forcibly enabling temp%d\n", i + 1); 15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pc87360_write_value(data, LD_TEMP, i, 15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PC87365_REG_TEMP_STATUS, 15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0xCF); 15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (use_thermistors) { 1509dedc6a7803d9c9795b504ffd8530a4ba7b3fd9edJim Cromie for (i = 11; i < data->innr; i++) { 15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (init >= init_in[i]) { 15113af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck /* 15123af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * The pin may already be used by thermal 15133af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * diodes 15143af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck */ 15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg = pc87360_read_value(data, LD_TEMP, 1516449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck (i - 11) / 2, PC87365_REG_TEMP_STATUS); 151728f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie if (reg & CHAN_ENA) { 1518449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck dev_dbg(&pdev->dev, 1519449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck "Skipping temp%d, pin already in use by temp%d\n", 1520449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck i - 7, (i - 11) / 2); 15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Forcibly enable thermistor channel */ 15251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg = pc87360_read_value(data, LD_IN, i, 15261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PC87365_REG_IN_STATUS); 152728f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie if (!(reg & CHAN_ENA)) { 1528449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck dev_dbg(&pdev->dev, 1529449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck "Forcibly enabling temp%d\n", 1530449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck i - 7); 15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pc87360_write_value(data, LD_IN, i, 15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PC87365_REG_TEMP_STATUS, 15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (reg & 0x60) | 0x8F); 15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->innr) { 15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg = pc87360_read_value(data, LD_IN, NO_BANK, 15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PC87365_REG_IN_CONFIG); 15428ca136741e15e8546e787ae92a7f4aeca84be494Jim Cromie dev_dbg(&pdev->dev, "bios vin-cfg:0x%02x\n", reg); 154328f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie if (reg & CHAN_ENA) { 1544449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck dev_dbg(&pdev->dev, 1545449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck "Forcibly enabling monitoring (VLM)\n"); 15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pc87360_write_value(data, LD_IN, NO_BANK, 15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PC87365_REG_IN_CONFIG, 15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg & 0xFE); 15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->tempnr) { 15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg = pc87360_read_value(data, LD_TEMP, NO_BANK, 15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PC87365_REG_TEMP_CONFIG); 15558ca136741e15e8546e787ae92a7f4aeca84be494Jim Cromie dev_dbg(&pdev->dev, "bios temp-cfg:0x%02x\n", reg); 155628f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie if (reg & CHAN_ENA) { 1557449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck dev_dbg(&pdev->dev, 1558449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck "Forcibly enabling monitoring (TMS)\n"); 15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pc87360_write_value(data, LD_TEMP, NO_BANK, 15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PC87365_REG_TEMP_CONFIG, 15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg & 0xFE); 15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (init >= 2) { 15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Chip config as documented by National Semi. */ 15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pc87360_write_value(data, LD_TEMP, 0xF, 0xA, 0x08); 15673af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck /* 15683af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * We voluntarily omit the bank here, in case the 15693af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * sequence itself matters. It shouldn't be a problem, 15703af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * since nobody else is supposed to access the 15713af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck * device at that point. 15723af2861e8b80676d32c5498f9ac1b2de70d3e19bGuenter Roeck */ 15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pc87360_write_value(data, LD_TEMP, NO_BANK, 0xB, 0x04); 15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pc87360_write_value(data, LD_TEMP, NO_BANK, 0xC, 0x35); 15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pc87360_write_value(data, LD_TEMP, NO_BANK, 0xD, 0x05); 15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pc87360_write_value(data, LD_TEMP, NO_BANK, 0xE, 0x05); 15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1581f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvarestatic void pc87360_autodiv(struct device *dev, int nr) 15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1583f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare struct pc87360_data *data = dev_get_drvdata(dev); 15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 old_min = data->fan_min[nr]; 15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Increase clock divider if needed and possible */ 15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((data->fan_status[nr] & 0x04) /* overflow flag */ 15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || (data->fan[nr] >= 224)) { /* next to overflow */ 15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((data->fan_status[nr] & 0x60) != 0x60) { 15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fan_status[nr] += 0x20; 15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fan_min[nr] >>= 1; 15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fan[nr] >>= 1; 1593f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare dev_dbg(dev, "Increasing " 15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "clock divider to %d for fan %d\n", 1595449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck FAN_DIV_FROM_REG(data->fan_status[nr]), nr + 1); 15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Decrease clock divider if possible */ 15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (!(data->fan_min[nr] & 0x80) /* min "nails" divider */ 16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && data->fan[nr] < 85 /* bad accuracy */ 16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && (data->fan_status[nr] & 0x60) != 0x00) { 16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fan_status[nr] -= 0x20; 16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fan_min[nr] <<= 1; 16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fan[nr] <<= 1; 1605f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare dev_dbg(dev, "Decreasing " 16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "clock divider to %d for fan %d\n", 16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FAN_DIV_FROM_REG(data->fan_status[nr]), 1608449a7a0720f2edc84288fb239bca8b2f9366881dGuenter Roeck nr + 1); 16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Write new fan min if it changed */ 16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (old_min != data->fan_min[nr]) { 16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pc87360_write_value(data, LD_FAN, NO_BANK, 16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PC87360_REG_FAN_MIN(nr), 16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fan_min[nr]); 16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pc87360_data *pc87360_update_device(struct device *dev) 16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1622f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare struct pc87360_data *data = dev_get_drvdata(dev); 16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 i; 16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16259a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_lock(&data->update_lock); 16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (time_after(jiffies, data->last_updated + HZ * 2) || !data->valid) { 1628f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare dev_dbg(dev, "Data update\n"); 16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Fans */ 16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < data->fannr; i++) { 16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (FAN_CONFIG_MONITOR(data->fan_conf, i)) { 16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fan_status[i] = 16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pc87360_read_value(data, LD_FAN, 16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NO_BANK, PC87360_REG_FAN_STATUS(i)); 16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fan[i] = pc87360_read_value(data, LD_FAN, 16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NO_BANK, PC87360_REG_FAN(i)); 16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fan_min[i] = pc87360_read_value(data, 16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LD_FAN, NO_BANK, 16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PC87360_REG_FAN_MIN(i)); 16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Change clock divider if needed */ 1642f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare pc87360_autodiv(dev, i); 16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Clear bits and write new divider */ 16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pc87360_write_value(data, LD_FAN, NO_BANK, 16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PC87360_REG_FAN_STATUS(i), 16461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fan_status[i]); 16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (FAN_CONFIG_CONTROL(data->fan_conf, i)) 16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->pwm[i] = pc87360_read_value(data, LD_FAN, 16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NO_BANK, PC87360_REG_PWM(i)); 16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Voltages */ 16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < data->innr; i++) { 16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->in_status[i] = pc87360_read_value(data, LD_IN, i, 16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PC87365_REG_IN_STATUS); 16571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Clear bits */ 16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pc87360_write_value(data, LD_IN, i, 16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PC87365_REG_IN_STATUS, 16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->in_status[i]); 166128f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie if ((data->in_status[i] & CHAN_READY) == CHAN_READY) { 16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->in[i] = pc87360_read_value(data, LD_IN, 16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i, PC87365_REG_IN); 16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 166528f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie if (data->in_status[i] & CHAN_ENA) { 16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->in_min[i] = pc87360_read_value(data, 16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LD_IN, i, 16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PC87365_REG_IN_MIN); 16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->in_max[i] = pc87360_read_value(data, 16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LD_IN, i, 16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PC87365_REG_IN_MAX); 16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i >= 11) 16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->in_crit[i-11] = 16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pc87360_read_value(data, LD_IN, 16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i, PC87365_REG_TEMP_CRIT); 16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->innr) { 16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->in_alarms = pc87360_read_value(data, LD_IN, 16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NO_BANK, PC87365_REG_IN_ALARMS1) 16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | ((pc87360_read_value(data, LD_IN, 16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NO_BANK, PC87365_REG_IN_ALARMS2) 16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds & 0x07) << 8); 16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->vid = (data->vid_conf & 0xE0) ? 16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pc87360_read_value(data, LD_IN, 16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NO_BANK, PC87365_REG_VID) : 0x1F; 16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Temperatures */ 16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < data->tempnr; i++) { 16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->temp_status[i] = pc87360_read_value(data, 16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LD_TEMP, i, 16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PC87365_REG_TEMP_STATUS); 16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Clear bits */ 16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pc87360_write_value(data, LD_TEMP, i, 16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PC87365_REG_TEMP_STATUS, 16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->temp_status[i]); 169828f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie if ((data->temp_status[i] & CHAN_READY) == CHAN_READY) { 16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->temp[i] = pc87360_read_value(data, 17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LD_TEMP, i, 17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PC87365_REG_TEMP); 17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 170328f74e71775b1ae0ebf7fe87f7a7f39ecb77a2b8Jim Cromie if (data->temp_status[i] & CHAN_ENA) { 17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->temp_min[i] = pc87360_read_value(data, 17051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LD_TEMP, i, 17061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PC87365_REG_TEMP_MIN); 17071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->temp_max[i] = pc87360_read_value(data, 17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LD_TEMP, i, 17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PC87365_REG_TEMP_MAX); 17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->temp_crit[i] = pc87360_read_value(data, 17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds LD_TEMP, i, 17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PC87365_REG_TEMP_CRIT); 17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->tempnr) { 17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->temp_alarms = pc87360_read_value(data, LD_TEMP, 17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds NO_BANK, PC87365_REG_TEMP_ALARMS) 17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds & 0x3F; 17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->last_updated = jiffies; 17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->valid = 1; 17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17259a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_unlock(&data->update_lock); 17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return data; 17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1730f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvarestatic int __init pc87360_device_add(unsigned short address) 1731f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare{ 1732b9783dcebe952bf73449fe70a19ee4814adc81a0Jean Delvare struct resource res[3]; 1733b9783dcebe952bf73449fe70a19ee4814adc81a0Jean Delvare int err, i, res_count; 1734f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare 1735f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare pdev = platform_device_alloc("pc87360", address); 1736f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare if (!pdev) { 1737f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare err = -ENOMEM; 17389e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches pr_err("Device allocation failed\n"); 1739f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare goto exit; 1740f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare } 1741f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare 1742b9783dcebe952bf73449fe70a19ee4814adc81a0Jean Delvare memset(res, 0, 3 * sizeof(struct resource)); 1743b9783dcebe952bf73449fe70a19ee4814adc81a0Jean Delvare res_count = 0; 1744f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare for (i = 0; i < 3; i++) { 1745f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare if (!extra_isa[i]) 1746f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare continue; 1747b9783dcebe952bf73449fe70a19ee4814adc81a0Jean Delvare res[res_count].start = extra_isa[i]; 1748b9783dcebe952bf73449fe70a19ee4814adc81a0Jean Delvare res[res_count].end = extra_isa[i] + PC87360_EXTENT - 1; 1749b9783dcebe952bf73449fe70a19ee4814adc81a0Jean Delvare res[res_count].name = "pc87360", 1750b9783dcebe952bf73449fe70a19ee4814adc81a0Jean Delvare res[res_count].flags = IORESOURCE_IO, 1751b9acb64a385c5b26fc392e0d58ac7b8e0a2cd812Jean Delvare 1752b9783dcebe952bf73449fe70a19ee4814adc81a0Jean Delvare err = acpi_check_resource_conflict(&res[res_count]); 1753b9acb64a385c5b26fc392e0d58ac7b8e0a2cd812Jean Delvare if (err) 1754b9acb64a385c5b26fc392e0d58ac7b8e0a2cd812Jean Delvare goto exit_device_put; 1755b9acb64a385c5b26fc392e0d58ac7b8e0a2cd812Jean Delvare 1756b9783dcebe952bf73449fe70a19ee4814adc81a0Jean Delvare res_count++; 1757b9783dcebe952bf73449fe70a19ee4814adc81a0Jean Delvare } 1758b9783dcebe952bf73449fe70a19ee4814adc81a0Jean Delvare 1759b9783dcebe952bf73449fe70a19ee4814adc81a0Jean Delvare err = platform_device_add_resources(pdev, res, res_count); 1760b9783dcebe952bf73449fe70a19ee4814adc81a0Jean Delvare if (err) { 17619e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches pr_err("Device resources addition failed (%d)\n", err); 1762b9783dcebe952bf73449fe70a19ee4814adc81a0Jean Delvare goto exit_device_put; 1763f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare } 1764f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare 1765f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare err = platform_device_add(pdev); 1766f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare if (err) { 17679e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches pr_err("Device addition failed (%d)\n", err); 1768f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare goto exit_device_put; 1769f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare } 1770f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare 1771f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare return 0; 1772f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare 1773f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvareexit_device_put: 1774f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare platform_device_put(pdev); 1775f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvareexit: 1776f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare return err; 1777f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare} 1778f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare 17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init pc87360_init(void) 17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1781f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare int err, i; 1782f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare unsigned short address = 0; 17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pc87360_find(0x2e, &devid, extra_isa) 17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds && pc87360_find(0x4e, &devid, extra_isa)) { 17869e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches pr_warn("PC8736x not detected, module not inserted\n"); 17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Arbitrarily pick one of the addresses */ 17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 3; i++) { 17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (extra_isa[i] != 0x0000) { 17932d8672c5a6ba0d3f1d8d3ad61ef67868941364f0Jean Delvare address = extra_isa[i]; 17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17982d8672c5a6ba0d3f1d8d3ad61ef67868941364f0Jean Delvare if (address == 0x0000) { 17999e991c6fad4618a9158437f1f650225f9ec485c3Joe Perches pr_warn("No active logical device, module not inserted\n"); 18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENODEV; 18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1803f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare err = platform_driver_register(&pc87360_driver); 1804f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare if (err) 1805f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare goto exit; 1806f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare 1807f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare /* Sets global pdev as a side effect */ 1808f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare err = pc87360_device_add(address); 1809f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare if (err) 1810f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare goto exit_driver; 1811f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare 1812f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare return 0; 1813f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare 1814f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare exit_driver: 1815f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare platform_driver_unregister(&pc87360_driver); 1816f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare exit: 1817f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare return err; 18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit pc87360_exit(void) 18211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1822f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare platform_device_unregister(pdev); 1823f641b588fdfd25e73c73f6e4977cd2daf8a5e363Jean Delvare platform_driver_unregister(&pc87360_driver); 18241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>"); 18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("PC8736x hardware monitor"); 18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(pc87360_init); 18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(pc87360_exit); 1833