1ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare/* 2ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare * pc87427.c - hardware monitoring driver for the 3ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare * National Semiconductor PC87427 Super-I/O chip 4008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare * Copyright (C) 2006, 2008, 2010 Jean Delvare <khali@linux-fr.org> 5ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare * 6ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare * This program is free software; you can redistribute it and/or modify 7ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare * it under the terms of the GNU General Public License version 2 as 8ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare * published by the Free Software Foundation. 9ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare * 10ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare * This program is distributed in the hope that it will be useful, 11ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare * but WITHOUT ANY WARRANTY; without even the implied warranty of 12ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare * GNU General Public License for more details. 14ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare * 15ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare * Supports the following chips: 16ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare * 17ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare * Chip #vin #fan #pwm #temp devid 18008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare * PC87427 - 8 4 6 0xF2 19ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare * 20ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare * This driver assumes that no more than one chip is present. 21008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare * Only fans are fully supported so far. Temperatures are in read-only 22008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare * mode, and voltages aren't supported at all. 23ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare */ 24ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 255e24e0c365e0f83f9a6f5adb3bd0cf5ca5cd8ab1Joe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 265e24e0c365e0f83f9a6f5adb3bd0cf5ca5cd8ab1Joe Perches 27ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare#include <linux/module.h> 28ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare#include <linux/init.h> 29ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare#include <linux/slab.h> 30ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare#include <linux/jiffies.h> 31ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare#include <linux/platform_device.h> 32ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare#include <linux/hwmon.h> 33ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare#include <linux/hwmon-sysfs.h> 34ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare#include <linux/err.h> 35ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare#include <linux/mutex.h> 36ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare#include <linux/sysfs.h> 37ce7ee4e80a72d3b1009ca232be8981de93c015f6Jean Delvare#include <linux/ioport.h> 38b9acb64a385c5b26fc392e0d58ac7b8e0a2cd812Jean Delvare#include <linux/acpi.h> 396055fae8aceee41471edfd1876e5617d16e028feH Hartley Sweeten#include <linux/io.h> 40ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 4167b671bceb4a8340a30929e9642620d99ed5ad76Jean Delvarestatic unsigned short force_id; 4267b671bceb4a8340a30929e9642620d99ed5ad76Jean Delvaremodule_param(force_id, ushort, 0); 4367b671bceb4a8340a30929e9642620d99ed5ad76Jean DelvareMODULE_PARM_DESC(force_id, "Override the detected device ID"); 4467b671bceb4a8340a30929e9642620d99ed5ad76Jean Delvare 45ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic struct platform_device *pdev; 46ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 47ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare#define DRVNAME "pc87427" 48ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 4936564efaddb7c1ace20f531860985a9848714c79Guenter Roeck/* 5036564efaddb7c1ace20f531860985a9848714c79Guenter Roeck * The lock mutex protects both the I/O accesses (needed because the 5136564efaddb7c1ace20f531860985a9848714c79Guenter Roeck * device is using banked registers) and the register cache (needed to keep 5236564efaddb7c1ace20f531860985a9848714c79Guenter Roeck * the data in the registers and the cache in sync at any time). 5336564efaddb7c1ace20f531860985a9848714c79Guenter Roeck */ 54ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestruct pc87427_data { 551beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones struct device *hwmon_dev; 56ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare struct mutex lock; 57ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare int address[2]; 58ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare const char *name; 59ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 60ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare unsigned long last_updated; /* in jiffies */ 61ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare u8 fan_enabled; /* bit vector */ 62ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare u16 fan[8]; /* register values */ 63ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare u16 fan_min[8]; /* register values */ 64ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare u8 fan_status[8]; /* register values */ 65328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare 66328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare u8 pwm_enabled; /* bit vector */ 67328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare u8 pwm_auto_ok; /* bit vector */ 68328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare u8 pwm_enable[4]; /* register values */ 69328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare u8 pwm[4]; /* register values */ 70008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 71008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare u8 temp_enabled; /* bit vector */ 72008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare s16 temp[6]; /* register values */ 73008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare s8 temp_min[6]; /* register values */ 74008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare s8 temp_max[6]; /* register values */ 75008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare s8 temp_crit[6]; /* register values */ 76008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare u8 temp_status[6]; /* register values */ 77008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare u8 temp_type[6]; /* register values */ 78ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare}; 79ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 804e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvarestruct pc87427_sio_data { 819d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare unsigned short address[2]; 824e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare u8 has_fanin; 83328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare u8 has_fanout; 844e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare}; 854e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare 86ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare/* 87ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare * Super-I/O registers and operations 88ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare */ 89ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 90ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare#define SIOREG_LDSEL 0x07 /* Logical device select */ 91ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare#define SIOREG_DEVID 0x20 /* Device ID */ 924e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare#define SIOREG_CF2 0x22 /* Configuration 2 */ 934e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare#define SIOREG_CF3 0x23 /* Configuration 3 */ 944e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare#define SIOREG_CF4 0x24 /* Configuration 4 */ 95328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare#define SIOREG_CF5 0x25 /* Configuration 5 */ 964e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare#define SIOREG_CFB 0x2B /* Configuration B */ 97328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare#define SIOREG_CFC 0x2C /* Configuration C */ 984e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare#define SIOREG_CFD 0x2D /* Configuration D */ 99ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare#define SIOREG_ACT 0x30 /* Device activation */ 100ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare#define SIOREG_MAP 0x50 /* I/O or memory mapping */ 101ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare#define SIOREG_IOBASE 0x60 /* I/O base address */ 102ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 103ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic const u8 logdev[2] = { 0x09, 0x14 }; 104ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic const char *logdev_str[2] = { DRVNAME " FMC", DRVNAME " HMC" }; 105ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare#define LD_FAN 0 106ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare#define LD_IN 1 107ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare#define LD_TEMP 1 108ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 109ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic inline void superio_outb(int sioaddr, int reg, int val) 110ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare{ 111ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare outb(reg, sioaddr); 112ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare outb(val, sioaddr + 1); 113ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare} 114ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 115ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic inline int superio_inb(int sioaddr, int reg) 116ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare{ 117ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare outb(reg, sioaddr); 118ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare return inb(sioaddr + 1); 119ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare} 120ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 121ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic inline void superio_exit(int sioaddr) 122ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare{ 123ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare outb(0x02, sioaddr); 124ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare outb(0x02, sioaddr + 1); 125ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare} 126ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 127ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare/* 128ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare * Logical devices 129ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare */ 130ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 131ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare#define REGION_LENGTH 32 132ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare#define PC87427_REG_BANK 0x0f 133ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare#define BANK_FM(nr) (nr) 134ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare#define BANK_FT(nr) (0x08 + (nr)) 135ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare#define BANK_FC(nr) (0x10 + (nr) * 2) 136008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare#define BANK_TM(nr) (nr) 137008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare#define BANK_VM(nr) (0x08 + (nr)) 138ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 139ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare/* 140ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare * I/O access functions 141ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare */ 142ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 143ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare/* ldi is the logical device index */ 144ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic inline int pc87427_read8(struct pc87427_data *data, u8 ldi, u8 reg) 145ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare{ 146ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare return inb(data->address[ldi] + reg); 147ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare} 148ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 149ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare/* Must be called with data->lock held, except during init */ 150ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic inline int pc87427_read8_bank(struct pc87427_data *data, u8 ldi, 151ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare u8 bank, u8 reg) 152ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare{ 153ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare outb(bank, data->address[ldi] + PC87427_REG_BANK); 154ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare return inb(data->address[ldi] + reg); 155ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare} 156ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 157ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare/* Must be called with data->lock held, except during init */ 158ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic inline void pc87427_write8_bank(struct pc87427_data *data, u8 ldi, 159ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare u8 bank, u8 reg, u8 value) 160ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare{ 161ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare outb(bank, data->address[ldi] + PC87427_REG_BANK); 162ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare outb(value, data->address[ldi] + reg); 163ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare} 164ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 165ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare/* 166ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare * Fan registers and conversions 167ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare */ 168ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 169ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare/* fan data registers are 16-bit wide */ 170ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare#define PC87427_REG_FAN 0x12 171ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare#define PC87427_REG_FAN_MIN 0x14 172ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare#define PC87427_REG_FAN_STATUS 0x10 173ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 174ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare#define FAN_STATUS_STALL (1 << 3) 175ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare#define FAN_STATUS_LOSPD (1 << 1) 176ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare#define FAN_STATUS_MONEN (1 << 0) 177ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 17836564efaddb7c1ace20f531860985a9848714c79Guenter Roeck/* 17936564efaddb7c1ace20f531860985a9848714c79Guenter Roeck * Dedicated function to read all registers related to a given fan input. 18036564efaddb7c1ace20f531860985a9848714c79Guenter Roeck * This saves us quite a few locks and bank selections. 18136564efaddb7c1ace20f531860985a9848714c79Guenter Roeck * Must be called with data->lock held. 18236564efaddb7c1ace20f531860985a9848714c79Guenter Roeck * nr is from 0 to 7 18336564efaddb7c1ace20f531860985a9848714c79Guenter Roeck */ 184ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic void pc87427_readall_fan(struct pc87427_data *data, u8 nr) 185ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare{ 186ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare int iobase = data->address[LD_FAN]; 187ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 188ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare outb(BANK_FM(nr), iobase + PC87427_REG_BANK); 189ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare data->fan[nr] = inw(iobase + PC87427_REG_FAN); 190ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare data->fan_min[nr] = inw(iobase + PC87427_REG_FAN_MIN); 191ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare data->fan_status[nr] = inb(iobase + PC87427_REG_FAN_STATUS); 192ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare /* Clear fan alarm bits */ 193ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare outb(data->fan_status[nr], iobase + PC87427_REG_FAN_STATUS); 194ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare} 195ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 19636564efaddb7c1ace20f531860985a9848714c79Guenter Roeck/* 19736564efaddb7c1ace20f531860985a9848714c79Guenter Roeck * The 2 LSB of fan speed registers are used for something different. 19836564efaddb7c1ace20f531860985a9848714c79Guenter Roeck * The actual 2 LSB of the measurements are not available. 19936564efaddb7c1ace20f531860985a9848714c79Guenter Roeck */ 200ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic inline unsigned long fan_from_reg(u16 reg) 201ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare{ 202ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare reg &= 0xfffc; 203ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare if (reg == 0x0000 || reg == 0xfffc) 204ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare return 0; 205ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare return 5400000UL / reg; 206ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare} 207ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 208ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare/* The 2 LSB of the fan speed limit registers are not significant. */ 209ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic inline u16 fan_to_reg(unsigned long val) 210ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare{ 211ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare if (val < 83UL) 212ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare return 0xffff; 213ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare if (val >= 1350000UL) 214ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare return 0x0004; 215ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare return ((1350000UL + val / 2) / val) << 2; 216ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare} 217ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 218ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare/* 219328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare * PWM registers and conversions 220328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare */ 221328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare 222328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare#define PC87427_REG_PWM_ENABLE 0x10 223328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare#define PC87427_REG_PWM_DUTY 0x12 224328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare 225328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare#define PWM_ENABLE_MODE_MASK (7 << 4) 226328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare#define PWM_ENABLE_CTLEN (1 << 0) 227328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare 228328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare#define PWM_MODE_MANUAL (0 << 4) 229328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare#define PWM_MODE_AUTO (1 << 4) 230328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare#define PWM_MODE_OFF (2 << 4) 231328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare#define PWM_MODE_ON (7 << 4) 232328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare 23336564efaddb7c1ace20f531860985a9848714c79Guenter Roeck/* 23436564efaddb7c1ace20f531860985a9848714c79Guenter Roeck * Dedicated function to read all registers related to a given PWM output. 23536564efaddb7c1ace20f531860985a9848714c79Guenter Roeck * This saves us quite a few locks and bank selections. 23636564efaddb7c1ace20f531860985a9848714c79Guenter Roeck * Must be called with data->lock held. 23736564efaddb7c1ace20f531860985a9848714c79Guenter Roeck * nr is from 0 to 3 23836564efaddb7c1ace20f531860985a9848714c79Guenter Roeck */ 239328716bc16b7077ea5f6293c7420247c570d6480Jean Delvarestatic void pc87427_readall_pwm(struct pc87427_data *data, u8 nr) 240328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare{ 241328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare int iobase = data->address[LD_FAN]; 242328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare 243328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare outb(BANK_FC(nr), iobase + PC87427_REG_BANK); 244328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare data->pwm_enable[nr] = inb(iobase + PC87427_REG_PWM_ENABLE); 245328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare data->pwm[nr] = inb(iobase + PC87427_REG_PWM_DUTY); 246328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare} 247328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare 248328716bc16b7077ea5f6293c7420247c570d6480Jean Delvarestatic inline int pwm_enable_from_reg(u8 reg) 249328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare{ 250328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare switch (reg & PWM_ENABLE_MODE_MASK) { 251328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare case PWM_MODE_ON: 252328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare return 0; 253328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare case PWM_MODE_MANUAL: 254328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare case PWM_MODE_OFF: 255328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare return 1; 256328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare case PWM_MODE_AUTO: 257328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare return 2; 258328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare default: 259328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare return -EPROTO; 260328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare } 261328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare} 262328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare 263328716bc16b7077ea5f6293c7420247c570d6480Jean Delvarestatic inline u8 pwm_enable_to_reg(unsigned long val, u8 pwmval) 264328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare{ 265328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare switch (val) { 266328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare default: 267328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare return PWM_MODE_ON; 268328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare case 1: 269328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare return pwmval ? PWM_MODE_MANUAL : PWM_MODE_OFF; 270328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare case 2: 271328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare return PWM_MODE_AUTO; 272328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare } 273328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare} 274328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare 275328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare/* 276008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare * Temperature registers and conversions 277008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare */ 278008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 279008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare#define PC87427_REG_TEMP_STATUS 0x10 280008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare#define PC87427_REG_TEMP 0x14 281008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare#define PC87427_REG_TEMP_MAX 0x18 282008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare#define PC87427_REG_TEMP_MIN 0x19 283008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare#define PC87427_REG_TEMP_CRIT 0x1a 284008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare#define PC87427_REG_TEMP_TYPE 0x1d 285008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 286008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare#define TEMP_STATUS_CHANEN (1 << 0) 287008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare#define TEMP_STATUS_LOWFLG (1 << 1) 288008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare#define TEMP_STATUS_HIGHFLG (1 << 2) 289008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare#define TEMP_STATUS_CRITFLG (1 << 3) 290008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare#define TEMP_STATUS_SENSERR (1 << 5) 291008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare#define TEMP_TYPE_MASK (3 << 5) 292008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 293008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare#define TEMP_TYPE_THERMISTOR (1 << 5) 294008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare#define TEMP_TYPE_REMOTE_DIODE (2 << 5) 295008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare#define TEMP_TYPE_LOCAL_DIODE (3 << 5) 296008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 29736564efaddb7c1ace20f531860985a9848714c79Guenter Roeck/* 29836564efaddb7c1ace20f531860985a9848714c79Guenter Roeck * Dedicated function to read all registers related to a given temperature 29936564efaddb7c1ace20f531860985a9848714c79Guenter Roeck * input. This saves us quite a few locks and bank selections. 30036564efaddb7c1ace20f531860985a9848714c79Guenter Roeck * Must be called with data->lock held. 30136564efaddb7c1ace20f531860985a9848714c79Guenter Roeck * nr is from 0 to 5 30236564efaddb7c1ace20f531860985a9848714c79Guenter Roeck */ 303008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic void pc87427_readall_temp(struct pc87427_data *data, u8 nr) 304008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare{ 305008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare int iobase = data->address[LD_TEMP]; 306008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 307008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare outb(BANK_TM(nr), iobase + PC87427_REG_BANK); 308008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare data->temp[nr] = le16_to_cpu(inw(iobase + PC87427_REG_TEMP)); 309008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare data->temp_max[nr] = inb(iobase + PC87427_REG_TEMP_MAX); 310008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare data->temp_min[nr] = inb(iobase + PC87427_REG_TEMP_MIN); 311008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare data->temp_crit[nr] = inb(iobase + PC87427_REG_TEMP_CRIT); 312008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare data->temp_type[nr] = inb(iobase + PC87427_REG_TEMP_TYPE); 313008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare data->temp_status[nr] = inb(iobase + PC87427_REG_TEMP_STATUS); 314008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare /* Clear fan alarm bits */ 315008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare outb(data->temp_status[nr], iobase + PC87427_REG_TEMP_STATUS); 316008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare} 317008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 318008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic inline unsigned int temp_type_from_reg(u8 reg) 319008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare{ 320008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare switch (reg & TEMP_TYPE_MASK) { 321008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare case TEMP_TYPE_THERMISTOR: 322008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare return 4; 323008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare case TEMP_TYPE_REMOTE_DIODE: 324008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare case TEMP_TYPE_LOCAL_DIODE: 325008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare return 3; 326008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare default: 327008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare return 0; 328008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare } 329008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare} 330008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 33136564efaddb7c1ace20f531860985a9848714c79Guenter Roeck/* 33236564efaddb7c1ace20f531860985a9848714c79Guenter Roeck * We assume 8-bit thermal sensors; 9-bit thermal sensors are possible 33336564efaddb7c1ace20f531860985a9848714c79Guenter Roeck * too, but I have no idea how to figure out when they are used. 33436564efaddb7c1ace20f531860985a9848714c79Guenter Roeck */ 335008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic inline long temp_from_reg(s16 reg) 336008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare{ 337008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare return reg * 1000 / 256; 338008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare} 339008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 340008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic inline long temp_from_reg8(s8 reg) 341008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare{ 342008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare return reg * 1000; 343008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare} 344008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 345008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare/* 346ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare * Data interface 347ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare */ 348ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 349ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic struct pc87427_data *pc87427_update_device(struct device *dev) 350ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare{ 351ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare struct pc87427_data *data = dev_get_drvdata(dev); 352ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare int i; 353ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 354ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare mutex_lock(&data->lock); 355ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare if (!time_after(jiffies, data->last_updated + HZ) 356ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare && data->last_updated) 357ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare goto done; 358ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 359ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare /* Fans */ 360ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare for (i = 0; i < 8; i++) { 361ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare if (!(data->fan_enabled & (1 << i))) 362ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare continue; 363ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare pc87427_readall_fan(data, i); 364ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare } 365328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare 366328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare /* PWM outputs */ 367328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare for (i = 0; i < 4; i++) { 368328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare if (!(data->pwm_enabled & (1 << i))) 369328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare continue; 370328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare pc87427_readall_pwm(data, i); 371328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare } 372328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare 373008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare /* Temperature channels */ 374008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare for (i = 0; i < 6; i++) { 375008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare if (!(data->temp_enabled & (1 << i))) 376008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare continue; 377008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare pc87427_readall_temp(data, i); 378008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare } 379008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 380ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare data->last_updated = jiffies; 381ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 382ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvaredone: 383ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare mutex_unlock(&data->lock); 384ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare return data; 385ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare} 386ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 387ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic ssize_t show_fan_input(struct device *dev, struct device_attribute 388ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare *devattr, char *buf) 389ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare{ 390ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare struct pc87427_data *data = pc87427_update_device(dev); 3910d22d5835d4c82d1d03399688267f63334efd526Jean Delvare int nr = to_sensor_dev_attr(devattr)->index; 392ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 393ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare return sprintf(buf, "%lu\n", fan_from_reg(data->fan[nr])); 394ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare} 395ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 396ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic ssize_t show_fan_min(struct device *dev, struct device_attribute 397ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare *devattr, char *buf) 398ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare{ 399ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare struct pc87427_data *data = pc87427_update_device(dev); 4000d22d5835d4c82d1d03399688267f63334efd526Jean Delvare int nr = to_sensor_dev_attr(devattr)->index; 401ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 402ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare return sprintf(buf, "%lu\n", fan_from_reg(data->fan_min[nr])); 403ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare} 404ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 405ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic ssize_t show_fan_alarm(struct device *dev, struct device_attribute 406ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare *devattr, char *buf) 407ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare{ 408ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare struct pc87427_data *data = pc87427_update_device(dev); 4090d22d5835d4c82d1d03399688267f63334efd526Jean Delvare int nr = to_sensor_dev_attr(devattr)->index; 410ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 411ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare return sprintf(buf, "%d\n", !!(data->fan_status[nr] 412ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare & FAN_STATUS_LOSPD)); 413ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare} 414ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 415ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic ssize_t show_fan_fault(struct device *dev, struct device_attribute 416ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare *devattr, char *buf) 417ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare{ 418ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare struct pc87427_data *data = pc87427_update_device(dev); 4190d22d5835d4c82d1d03399688267f63334efd526Jean Delvare int nr = to_sensor_dev_attr(devattr)->index; 420ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 421ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare return sprintf(buf, "%d\n", !!(data->fan_status[nr] 422ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare & FAN_STATUS_STALL)); 423ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare} 424ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 425ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic ssize_t set_fan_min(struct device *dev, struct device_attribute 426ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare *devattr, const char *buf, size_t count) 427ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare{ 428ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare struct pc87427_data *data = dev_get_drvdata(dev); 4290d22d5835d4c82d1d03399688267f63334efd526Jean Delvare int nr = to_sensor_dev_attr(devattr)->index; 4300d22d5835d4c82d1d03399688267f63334efd526Jean Delvare unsigned long val; 431ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare int iobase = data->address[LD_FAN]; 432ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 433179c4fdb565dd2157e5dfe89318b74868e3b523dFrans Meulenbroeks if (kstrtoul(buf, 10, &val) < 0) 4340d22d5835d4c82d1d03399688267f63334efd526Jean Delvare return -EINVAL; 4350d22d5835d4c82d1d03399688267f63334efd526Jean Delvare 436ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare mutex_lock(&data->lock); 437ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare outb(BANK_FM(nr), iobase + PC87427_REG_BANK); 43836564efaddb7c1ace20f531860985a9848714c79Guenter Roeck /* 43936564efaddb7c1ace20f531860985a9848714c79Guenter Roeck * The low speed limit registers are read-only while monitoring 44036564efaddb7c1ace20f531860985a9848714c79Guenter Roeck * is enabled, so we have to disable monitoring, then change the 44136564efaddb7c1ace20f531860985a9848714c79Guenter Roeck * limit, and finally enable monitoring again. 44236564efaddb7c1ace20f531860985a9848714c79Guenter Roeck */ 443ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare outb(0, iobase + PC87427_REG_FAN_STATUS); 444ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare data->fan_min[nr] = fan_to_reg(val); 445ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare outw(data->fan_min[nr], iobase + PC87427_REG_FAN_MIN); 446ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare outb(FAN_STATUS_MONEN, iobase + PC87427_REG_FAN_STATUS); 447ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare mutex_unlock(&data->lock); 448ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 449ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare return count; 450ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare} 451ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 452ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan_input, NULL, 0); 453ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan_input, NULL, 1); 454ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan_input, NULL, 2); 455ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan_input, NULL, 3); 456ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic SENSOR_DEVICE_ATTR(fan5_input, S_IRUGO, show_fan_input, NULL, 4); 457ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic SENSOR_DEVICE_ATTR(fan6_input, S_IRUGO, show_fan_input, NULL, 5); 458ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic SENSOR_DEVICE_ATTR(fan7_input, S_IRUGO, show_fan_input, NULL, 6); 459ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic SENSOR_DEVICE_ATTR(fan8_input, S_IRUGO, show_fan_input, NULL, 7); 460ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 461ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, 462ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare show_fan_min, set_fan_min, 0); 463ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO, 464ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare show_fan_min, set_fan_min, 1); 465ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic SENSOR_DEVICE_ATTR(fan3_min, S_IWUSR | S_IRUGO, 466ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare show_fan_min, set_fan_min, 2); 467ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic SENSOR_DEVICE_ATTR(fan4_min, S_IWUSR | S_IRUGO, 468ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare show_fan_min, set_fan_min, 3); 469ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic SENSOR_DEVICE_ATTR(fan5_min, S_IWUSR | S_IRUGO, 470ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare show_fan_min, set_fan_min, 4); 471ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic SENSOR_DEVICE_ATTR(fan6_min, S_IWUSR | S_IRUGO, 472ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare show_fan_min, set_fan_min, 5); 473ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic SENSOR_DEVICE_ATTR(fan7_min, S_IWUSR | S_IRUGO, 474ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare show_fan_min, set_fan_min, 6); 475ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic SENSOR_DEVICE_ATTR(fan8_min, S_IWUSR | S_IRUGO, 476ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare show_fan_min, set_fan_min, 7); 477ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 478ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_fan_alarm, NULL, 0); 479ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_fan_alarm, NULL, 1); 480ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_fan_alarm, NULL, 2); 481ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic SENSOR_DEVICE_ATTR(fan4_alarm, S_IRUGO, show_fan_alarm, NULL, 3); 482ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic SENSOR_DEVICE_ATTR(fan5_alarm, S_IRUGO, show_fan_alarm, NULL, 4); 483ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic SENSOR_DEVICE_ATTR(fan6_alarm, S_IRUGO, show_fan_alarm, NULL, 5); 484ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic SENSOR_DEVICE_ATTR(fan7_alarm, S_IRUGO, show_fan_alarm, NULL, 6); 485ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic SENSOR_DEVICE_ATTR(fan8_alarm, S_IRUGO, show_fan_alarm, NULL, 7); 486ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 487ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, show_fan_fault, NULL, 0); 488ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic SENSOR_DEVICE_ATTR(fan2_fault, S_IRUGO, show_fan_fault, NULL, 1); 489ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic SENSOR_DEVICE_ATTR(fan3_fault, S_IRUGO, show_fan_fault, NULL, 2); 490ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic SENSOR_DEVICE_ATTR(fan4_fault, S_IRUGO, show_fan_fault, NULL, 3); 491ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic SENSOR_DEVICE_ATTR(fan5_fault, S_IRUGO, show_fan_fault, NULL, 4); 492ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic SENSOR_DEVICE_ATTR(fan6_fault, S_IRUGO, show_fan_fault, NULL, 5); 493ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic SENSOR_DEVICE_ATTR(fan7_fault, S_IRUGO, show_fan_fault, NULL, 6); 494ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic SENSOR_DEVICE_ATTR(fan8_fault, S_IRUGO, show_fan_fault, NULL, 7); 495ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 496ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic struct attribute *pc87427_attributes_fan[8][5] = { 497ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare { 498ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare &sensor_dev_attr_fan1_input.dev_attr.attr, 499ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare &sensor_dev_attr_fan1_min.dev_attr.attr, 500ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare &sensor_dev_attr_fan1_alarm.dev_attr.attr, 501ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare &sensor_dev_attr_fan1_fault.dev_attr.attr, 502ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare NULL 503ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare }, { 504ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare &sensor_dev_attr_fan2_input.dev_attr.attr, 505ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare &sensor_dev_attr_fan2_min.dev_attr.attr, 506ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare &sensor_dev_attr_fan2_alarm.dev_attr.attr, 507ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare &sensor_dev_attr_fan2_fault.dev_attr.attr, 508ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare NULL 509ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare }, { 510ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare &sensor_dev_attr_fan3_input.dev_attr.attr, 511ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare &sensor_dev_attr_fan3_min.dev_attr.attr, 512ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare &sensor_dev_attr_fan3_alarm.dev_attr.attr, 513ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare &sensor_dev_attr_fan3_fault.dev_attr.attr, 514ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare NULL 515ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare }, { 516ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare &sensor_dev_attr_fan4_input.dev_attr.attr, 517ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare &sensor_dev_attr_fan4_min.dev_attr.attr, 518ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare &sensor_dev_attr_fan4_alarm.dev_attr.attr, 519ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare &sensor_dev_attr_fan4_fault.dev_attr.attr, 520ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare NULL 521ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare }, { 522ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare &sensor_dev_attr_fan5_input.dev_attr.attr, 523ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare &sensor_dev_attr_fan5_min.dev_attr.attr, 524ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare &sensor_dev_attr_fan5_alarm.dev_attr.attr, 525ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare &sensor_dev_attr_fan5_fault.dev_attr.attr, 526ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare NULL 527ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare }, { 528ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare &sensor_dev_attr_fan6_input.dev_attr.attr, 529ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare &sensor_dev_attr_fan6_min.dev_attr.attr, 530ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare &sensor_dev_attr_fan6_alarm.dev_attr.attr, 531ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare &sensor_dev_attr_fan6_fault.dev_attr.attr, 532ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare NULL 533ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare }, { 534ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare &sensor_dev_attr_fan7_input.dev_attr.attr, 535ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare &sensor_dev_attr_fan7_min.dev_attr.attr, 536ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare &sensor_dev_attr_fan7_alarm.dev_attr.attr, 537ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare &sensor_dev_attr_fan7_fault.dev_attr.attr, 538ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare NULL 539ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare }, { 540ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare &sensor_dev_attr_fan8_input.dev_attr.attr, 541ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare &sensor_dev_attr_fan8_min.dev_attr.attr, 542ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare &sensor_dev_attr_fan8_alarm.dev_attr.attr, 543ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare &sensor_dev_attr_fan8_fault.dev_attr.attr, 544ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare NULL 545ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare } 546ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare}; 547ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 548ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic const struct attribute_group pc87427_group_fan[8] = { 549ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare { .attrs = pc87427_attributes_fan[0] }, 550ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare { .attrs = pc87427_attributes_fan[1] }, 551ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare { .attrs = pc87427_attributes_fan[2] }, 552ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare { .attrs = pc87427_attributes_fan[3] }, 553ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare { .attrs = pc87427_attributes_fan[4] }, 554ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare { .attrs = pc87427_attributes_fan[5] }, 555ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare { .attrs = pc87427_attributes_fan[6] }, 556ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare { .attrs = pc87427_attributes_fan[7] }, 557ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare}; 558ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 55936564efaddb7c1ace20f531860985a9848714c79Guenter Roeck/* 56036564efaddb7c1ace20f531860985a9848714c79Guenter Roeck * Must be called with data->lock held and pc87427_readall_pwm() freshly 56136564efaddb7c1ace20f531860985a9848714c79Guenter Roeck * called 56236564efaddb7c1ace20f531860985a9848714c79Guenter Roeck */ 563328716bc16b7077ea5f6293c7420247c570d6480Jean Delvarestatic void update_pwm_enable(struct pc87427_data *data, int nr, u8 mode) 564328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare{ 565328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare int iobase = data->address[LD_FAN]; 566328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare data->pwm_enable[nr] &= ~PWM_ENABLE_MODE_MASK; 567328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare data->pwm_enable[nr] |= mode; 568328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare outb(data->pwm_enable[nr], iobase + PC87427_REG_PWM_ENABLE); 569328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare} 570328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare 571328716bc16b7077ea5f6293c7420247c570d6480Jean Delvarestatic ssize_t show_pwm_enable(struct device *dev, struct device_attribute 572328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare *devattr, char *buf) 573328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare{ 574328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare struct pc87427_data *data = pc87427_update_device(dev); 575328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare int nr = to_sensor_dev_attr(devattr)->index; 576328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare int pwm_enable; 577328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare 578328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare pwm_enable = pwm_enable_from_reg(data->pwm_enable[nr]); 579328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare if (pwm_enable < 0) 580328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare return pwm_enable; 581328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare return sprintf(buf, "%d\n", pwm_enable); 582328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare} 583328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare 584328716bc16b7077ea5f6293c7420247c570d6480Jean Delvarestatic ssize_t set_pwm_enable(struct device *dev, struct device_attribute 585328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare *devattr, const char *buf, size_t count) 586328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare{ 587328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare struct pc87427_data *data = dev_get_drvdata(dev); 588328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare int nr = to_sensor_dev_attr(devattr)->index; 589328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare unsigned long val; 590328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare 591179c4fdb565dd2157e5dfe89318b74868e3b523dFrans Meulenbroeks if (kstrtoul(buf, 10, &val) < 0 || val > 2) 592328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare return -EINVAL; 593328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare /* Can't go to automatic mode if it isn't configured */ 594328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare if (val == 2 && !(data->pwm_auto_ok & (1 << nr))) 595328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare return -EINVAL; 596328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare 597328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare mutex_lock(&data->lock); 598328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare pc87427_readall_pwm(data, nr); 599328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare update_pwm_enable(data, nr, pwm_enable_to_reg(val, data->pwm[nr])); 600328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare mutex_unlock(&data->lock); 601328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare 602328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare return count; 603328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare} 604328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare 605328716bc16b7077ea5f6293c7420247c570d6480Jean Delvarestatic ssize_t show_pwm(struct device *dev, struct device_attribute 606328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare *devattr, char *buf) 607328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare{ 608328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare struct pc87427_data *data = pc87427_update_device(dev); 609328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare int nr = to_sensor_dev_attr(devattr)->index; 610328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare 611328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare return sprintf(buf, "%d\n", (int)data->pwm[nr]); 612328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare} 613328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare 614328716bc16b7077ea5f6293c7420247c570d6480Jean Delvarestatic ssize_t set_pwm(struct device *dev, struct device_attribute 615328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare *devattr, const char *buf, size_t count) 616328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare{ 617328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare struct pc87427_data *data = dev_get_drvdata(dev); 618328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare int nr = to_sensor_dev_attr(devattr)->index; 619328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare unsigned long val; 620328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare int iobase = data->address[LD_FAN]; 621328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare u8 mode; 622328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare 623179c4fdb565dd2157e5dfe89318b74868e3b523dFrans Meulenbroeks if (kstrtoul(buf, 10, &val) < 0 || val > 0xff) 624328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare return -EINVAL; 625328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare 626328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare mutex_lock(&data->lock); 627328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare pc87427_readall_pwm(data, nr); 628328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare mode = data->pwm_enable[nr] & PWM_ENABLE_MODE_MASK; 629328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare if (mode != PWM_MODE_MANUAL && mode != PWM_MODE_OFF) { 630328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare dev_notice(dev, "Can't set PWM%d duty cycle while not in " 631328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare "manual mode\n", nr + 1); 632328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare mutex_unlock(&data->lock); 633328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare return -EPERM; 634328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare } 635328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare 636328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare /* We may have to change the mode */ 637328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare if (mode == PWM_MODE_MANUAL && val == 0) { 638328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare /* Transition from Manual to Off */ 639328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare update_pwm_enable(data, nr, PWM_MODE_OFF); 640328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare mode = PWM_MODE_OFF; 641328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare dev_dbg(dev, "Switching PWM%d from %s to %s\n", nr + 1, 642328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare "manual", "off"); 643328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare } else if (mode == PWM_MODE_OFF && val != 0) { 644328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare /* Transition from Off to Manual */ 645328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare update_pwm_enable(data, nr, PWM_MODE_MANUAL); 646328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare mode = PWM_MODE_MANUAL; 647328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare dev_dbg(dev, "Switching PWM%d from %s to %s\n", nr + 1, 648328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare "off", "manual"); 649328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare } 650328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare 651328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare data->pwm[nr] = val; 652328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare if (mode == PWM_MODE_MANUAL) 653328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare outb(val, iobase + PC87427_REG_PWM_DUTY); 654328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare mutex_unlock(&data->lock); 655328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare 656328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare return count; 657328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare} 658328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare 659328716bc16b7077ea5f6293c7420247c570d6480Jean Delvarestatic SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, 660328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare show_pwm_enable, set_pwm_enable, 0); 661328716bc16b7077ea5f6293c7420247c570d6480Jean Delvarestatic SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, 662328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare show_pwm_enable, set_pwm_enable, 1); 663328716bc16b7077ea5f6293c7420247c570d6480Jean Delvarestatic SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, 664328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare show_pwm_enable, set_pwm_enable, 2); 665328716bc16b7077ea5f6293c7420247c570d6480Jean Delvarestatic SENSOR_DEVICE_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, 666328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare show_pwm_enable, set_pwm_enable, 3); 667328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare 668328716bc16b7077ea5f6293c7420247c570d6480Jean Delvarestatic SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 0); 669328716bc16b7077ea5f6293c7420247c570d6480Jean Delvarestatic SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 1); 670328716bc16b7077ea5f6293c7420247c570d6480Jean Delvarestatic SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2); 671328716bc16b7077ea5f6293c7420247c570d6480Jean Delvarestatic SENSOR_DEVICE_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 3); 672328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare 673328716bc16b7077ea5f6293c7420247c570d6480Jean Delvarestatic struct attribute *pc87427_attributes_pwm[4][3] = { 674328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare { 675328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare &sensor_dev_attr_pwm1_enable.dev_attr.attr, 676328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare &sensor_dev_attr_pwm1.dev_attr.attr, 677328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare NULL 678328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare }, { 679328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare &sensor_dev_attr_pwm2_enable.dev_attr.attr, 680328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare &sensor_dev_attr_pwm2.dev_attr.attr, 681328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare NULL 682328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare }, { 683328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare &sensor_dev_attr_pwm3_enable.dev_attr.attr, 684328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare &sensor_dev_attr_pwm3.dev_attr.attr, 685328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare NULL 686328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare }, { 687328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare &sensor_dev_attr_pwm4_enable.dev_attr.attr, 688328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare &sensor_dev_attr_pwm4.dev_attr.attr, 689328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare NULL 690328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare } 691328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare}; 692328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare 693328716bc16b7077ea5f6293c7420247c570d6480Jean Delvarestatic const struct attribute_group pc87427_group_pwm[4] = { 694328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare { .attrs = pc87427_attributes_pwm[0] }, 695328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare { .attrs = pc87427_attributes_pwm[1] }, 696328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare { .attrs = pc87427_attributes_pwm[2] }, 697328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare { .attrs = pc87427_attributes_pwm[3] }, 698328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare}; 699328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare 700008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic ssize_t show_temp_input(struct device *dev, struct device_attribute 701008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare *devattr, char *buf) 702008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare{ 703008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare struct pc87427_data *data = pc87427_update_device(dev); 704008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare int nr = to_sensor_dev_attr(devattr)->index; 705008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 706008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare return sprintf(buf, "%ld\n", temp_from_reg(data->temp[nr])); 707008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare} 708008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 709008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic ssize_t show_temp_min(struct device *dev, struct device_attribute 710008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare *devattr, char *buf) 711008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare{ 712008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare struct pc87427_data *data = pc87427_update_device(dev); 713008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare int nr = to_sensor_dev_attr(devattr)->index; 714008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 715008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare return sprintf(buf, "%ld\n", temp_from_reg8(data->temp_min[nr])); 716008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare} 717008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 718008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic ssize_t show_temp_max(struct device *dev, struct device_attribute 719008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare *devattr, char *buf) 720008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare{ 721008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare struct pc87427_data *data = pc87427_update_device(dev); 722008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare int nr = to_sensor_dev_attr(devattr)->index; 723008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 724008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare return sprintf(buf, "%ld\n", temp_from_reg8(data->temp_max[nr])); 725008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare} 726008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 727008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic ssize_t show_temp_crit(struct device *dev, struct device_attribute 728008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare *devattr, char *buf) 729008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare{ 730008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare struct pc87427_data *data = pc87427_update_device(dev); 731008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare int nr = to_sensor_dev_attr(devattr)->index; 732008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 733008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare return sprintf(buf, "%ld\n", temp_from_reg8(data->temp_crit[nr])); 734008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare} 735008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 736008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic ssize_t show_temp_type(struct device *dev, struct device_attribute 737008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare *devattr, char *buf) 738008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare{ 739008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare struct pc87427_data *data = pc87427_update_device(dev); 740008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare int nr = to_sensor_dev_attr(devattr)->index; 741008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 742008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare return sprintf(buf, "%u\n", temp_type_from_reg(data->temp_type[nr])); 743008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare} 744008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 745008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic ssize_t show_temp_min_alarm(struct device *dev, struct device_attribute 746008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare *devattr, char *buf) 747008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare{ 748008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare struct pc87427_data *data = pc87427_update_device(dev); 749008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare int nr = to_sensor_dev_attr(devattr)->index; 750008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 751008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare return sprintf(buf, "%d\n", !!(data->temp_status[nr] 752008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare & TEMP_STATUS_LOWFLG)); 753008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare} 754008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 755008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic ssize_t show_temp_max_alarm(struct device *dev, struct device_attribute 756008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare *devattr, char *buf) 757008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare{ 758008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare struct pc87427_data *data = pc87427_update_device(dev); 759008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare int nr = to_sensor_dev_attr(devattr)->index; 760008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 761008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare return sprintf(buf, "%d\n", !!(data->temp_status[nr] 762008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare & TEMP_STATUS_HIGHFLG)); 763008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare} 764008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 765008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic ssize_t show_temp_crit_alarm(struct device *dev, struct device_attribute 766008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare *devattr, char *buf) 767008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare{ 768008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare struct pc87427_data *data = pc87427_update_device(dev); 769008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare int nr = to_sensor_dev_attr(devattr)->index; 770008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 771008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare return sprintf(buf, "%d\n", !!(data->temp_status[nr] 772008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare & TEMP_STATUS_CRITFLG)); 773008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare} 774008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 775008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic ssize_t show_temp_fault(struct device *dev, struct device_attribute 776008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare *devattr, char *buf) 777008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare{ 778008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare struct pc87427_data *data = pc87427_update_device(dev); 779008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare int nr = to_sensor_dev_attr(devattr)->index; 780008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 781008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare return sprintf(buf, "%d\n", !!(data->temp_status[nr] 782008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare & TEMP_STATUS_SENSERR)); 783008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare} 784008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 785008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL, 0); 786008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp_input, NULL, 1); 787008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp_input, NULL, 2); 788008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp_input, NULL, 3); 789008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_temp_input, NULL, 4); 790008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, show_temp_input, NULL, 5); 791008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 792008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO, show_temp_min, NULL, 0); 793008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp2_min, S_IRUGO, show_temp_min, NULL, 1); 794008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp3_min, S_IRUGO, show_temp_min, NULL, 2); 795008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp4_min, S_IRUGO, show_temp_min, NULL, 3); 796008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp5_min, S_IRUGO, show_temp_min, NULL, 4); 797008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp6_min, S_IRUGO, show_temp_min, NULL, 5); 798008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 799008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO, show_temp_max, NULL, 0); 800008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO, show_temp_max, NULL, 1); 801008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp3_max, S_IRUGO, show_temp_max, NULL, 2); 802008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp4_max, S_IRUGO, show_temp_max, NULL, 3); 803008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp5_max, S_IRUGO, show_temp_max, NULL, 4); 804008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp6_max, S_IRUGO, show_temp_max, NULL, 5); 805008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 806008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, show_temp_crit, NULL, 0); 807008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO, show_temp_crit, NULL, 1); 808008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp3_crit, S_IRUGO, show_temp_crit, NULL, 2); 809008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp4_crit, S_IRUGO, show_temp_crit, NULL, 3); 810008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp5_crit, S_IRUGO, show_temp_crit, NULL, 4); 811008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp6_crit, S_IRUGO, show_temp_crit, NULL, 5); 812008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 813008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp1_type, S_IRUGO, show_temp_type, NULL, 0); 814008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO, show_temp_type, NULL, 1); 815008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO, show_temp_type, NULL, 2); 816008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp4_type, S_IRUGO, show_temp_type, NULL, 3); 817008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp5_type, S_IRUGO, show_temp_type, NULL, 4); 818008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp6_type, S_IRUGO, show_temp_type, NULL, 5); 819008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 820008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, 821008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare show_temp_min_alarm, NULL, 0); 822008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, 823008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare show_temp_min_alarm, NULL, 1); 824008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp3_min_alarm, S_IRUGO, 825008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare show_temp_min_alarm, NULL, 2); 826008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp4_min_alarm, S_IRUGO, 827008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare show_temp_min_alarm, NULL, 3); 828008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp5_min_alarm, S_IRUGO, 829008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare show_temp_min_alarm, NULL, 4); 830008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp6_min_alarm, S_IRUGO, 831008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare show_temp_min_alarm, NULL, 5); 832008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 833008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, 834008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare show_temp_max_alarm, NULL, 0); 835008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, 836008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare show_temp_max_alarm, NULL, 1); 837008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, 838008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare show_temp_max_alarm, NULL, 2); 839008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, 840008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare show_temp_max_alarm, NULL, 3); 841008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp5_max_alarm, S_IRUGO, 842008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare show_temp_max_alarm, NULL, 4); 843008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp6_max_alarm, S_IRUGO, 844008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare show_temp_max_alarm, NULL, 5); 845008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 846008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, 847008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare show_temp_crit_alarm, NULL, 0); 848008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, 849008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare show_temp_crit_alarm, NULL, 1); 850008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp3_crit_alarm, S_IRUGO, 851008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare show_temp_crit_alarm, NULL, 2); 852008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp4_crit_alarm, S_IRUGO, 853008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare show_temp_crit_alarm, NULL, 3); 854008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp5_crit_alarm, S_IRUGO, 855008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare show_temp_crit_alarm, NULL, 4); 856008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp6_crit_alarm, S_IRUGO, 857008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare show_temp_crit_alarm, NULL, 5); 858008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 859008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, show_temp_fault, NULL, 0); 860008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_temp_fault, NULL, 1); 861008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_temp_fault, NULL, 2); 862008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp4_fault, S_IRUGO, show_temp_fault, NULL, 3); 863008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp5_fault, S_IRUGO, show_temp_fault, NULL, 4); 864008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic SENSOR_DEVICE_ATTR(temp6_fault, S_IRUGO, show_temp_fault, NULL, 5); 865008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 866008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic struct attribute *pc87427_attributes_temp[6][10] = { 867008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare { 868008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp1_input.dev_attr.attr, 869008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp1_min.dev_attr.attr, 870008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp1_max.dev_attr.attr, 871008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp1_crit.dev_attr.attr, 872008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp1_type.dev_attr.attr, 873008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, 874008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, 875008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, 876008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp1_fault.dev_attr.attr, 877008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare NULL 878008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare }, { 879008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp2_input.dev_attr.attr, 880008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp2_min.dev_attr.attr, 881008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp2_max.dev_attr.attr, 882008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp2_crit.dev_attr.attr, 883008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp2_type.dev_attr.attr, 884008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp2_min_alarm.dev_attr.attr, 885008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, 886008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr, 887008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp2_fault.dev_attr.attr, 888008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare NULL 889008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare }, { 890008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp3_input.dev_attr.attr, 891008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp3_min.dev_attr.attr, 892008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp3_max.dev_attr.attr, 893008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp3_crit.dev_attr.attr, 894008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp3_type.dev_attr.attr, 895008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp3_min_alarm.dev_attr.attr, 896008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp3_max_alarm.dev_attr.attr, 897008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr, 898008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp3_fault.dev_attr.attr, 899008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare NULL 900008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare }, { 901008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp4_input.dev_attr.attr, 902008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp4_min.dev_attr.attr, 903008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp4_max.dev_attr.attr, 904008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp4_crit.dev_attr.attr, 905008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp4_type.dev_attr.attr, 906008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp4_min_alarm.dev_attr.attr, 907008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp4_max_alarm.dev_attr.attr, 908008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp4_crit_alarm.dev_attr.attr, 909008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp4_fault.dev_attr.attr, 910008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare NULL 911008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare }, { 912008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp5_input.dev_attr.attr, 913008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp5_min.dev_attr.attr, 914008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp5_max.dev_attr.attr, 915008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp5_crit.dev_attr.attr, 916008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp5_type.dev_attr.attr, 917008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp5_min_alarm.dev_attr.attr, 918008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp5_max_alarm.dev_attr.attr, 919008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp5_crit_alarm.dev_attr.attr, 920008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp5_fault.dev_attr.attr, 921008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare NULL 922008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare }, { 923008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp6_input.dev_attr.attr, 924008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp6_min.dev_attr.attr, 925008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp6_max.dev_attr.attr, 926008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp6_crit.dev_attr.attr, 927008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp6_type.dev_attr.attr, 928008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp6_min_alarm.dev_attr.attr, 929008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp6_max_alarm.dev_attr.attr, 930008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp6_crit_alarm.dev_attr.attr, 931008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &sensor_dev_attr_temp6_fault.dev_attr.attr, 932008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare NULL 933008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare } 934008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare}; 935008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 936008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvarestatic const struct attribute_group pc87427_group_temp[6] = { 937008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare { .attrs = pc87427_attributes_temp[0] }, 938008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare { .attrs = pc87427_attributes_temp[1] }, 939008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare { .attrs = pc87427_attributes_temp[2] }, 940008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare { .attrs = pc87427_attributes_temp[3] }, 941008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare { .attrs = pc87427_attributes_temp[4] }, 942008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare { .attrs = pc87427_attributes_temp[5] }, 943008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare}; 944008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 945ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic ssize_t show_name(struct device *dev, struct device_attribute 946ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare *devattr, char *buf) 947ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare{ 948ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare struct pc87427_data *data = dev_get_drvdata(dev); 949ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 950ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare return sprintf(buf, "%s\n", data->name); 951ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare} 952ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic DEVICE_ATTR(name, S_IRUGO, show_name, NULL); 953ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 954ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 955ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare/* 956ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare * Device detection, attach and detach 957ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare */ 958ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 9599d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvarestatic void pc87427_release_regions(struct platform_device *pdev, int count) 9609d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare{ 9619d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare struct resource *res; 9629d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare int i; 9639d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare 9649d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare for (i = 0; i < count; i++) { 9659d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare res = platform_get_resource(pdev, IORESOURCE_IO, i); 9669d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare release_region(res->start, resource_size(res)); 9679d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare } 9689d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare} 9699d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare 9709d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvarestatic int __devinit pc87427_request_regions(struct platform_device *pdev, 9719d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare int count) 9729d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare{ 9739d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare struct resource *res; 9749d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare int i, err = 0; 9759d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare 9769d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare for (i = 0; i < count; i++) { 9779d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare res = platform_get_resource(pdev, IORESOURCE_IO, i); 9789d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare if (!res) { 9799d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare err = -ENOENT; 9809d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare dev_err(&pdev->dev, "Missing resource #%d\n", i); 9819d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare break; 9829d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare } 9839d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare if (!request_region(res->start, resource_size(res), DRVNAME)) { 9849d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare err = -EBUSY; 9859d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare dev_err(&pdev->dev, 9869d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare "Failed to request region 0x%lx-0x%lx\n", 9879d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare (unsigned long)res->start, 9889d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare (unsigned long)res->end); 9899d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare break; 9909d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare } 9919d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare } 9929d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare 9939d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare if (err && i) 9949d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare pc87427_release_regions(pdev, i); 9959d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare 9969d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare return err; 9979d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare} 9989d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare 999ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic void __devinit pc87427_init_device(struct device *dev) 1000ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare{ 10014e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare struct pc87427_sio_data *sio_data = dev->platform_data; 1002ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare struct pc87427_data *data = dev_get_drvdata(dev); 1003ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare int i; 1004ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare u8 reg; 1005ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 1006ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare /* The FMC module should be ready */ 1007ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare reg = pc87427_read8(data, LD_FAN, PC87427_REG_BANK); 1008ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare if (!(reg & 0x80)) 1009008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare dev_warn(dev, "%s module not ready!\n", "FMC"); 1010ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 1011ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare /* Check which fans are enabled */ 1012ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare for (i = 0; i < 8; i++) { 10134e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare if (!(sio_data->has_fanin & (1 << i))) /* Not wired */ 10144e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare continue; 1015ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare reg = pc87427_read8_bank(data, LD_FAN, BANK_FM(i), 1016ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare PC87427_REG_FAN_STATUS); 1017ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare if (reg & FAN_STATUS_MONEN) 1018ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare data->fan_enabled |= (1 << i); 1019ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare } 1020ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 1021ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare if (!data->fan_enabled) { 10224e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare dev_dbg(dev, "Enabling monitoring of all fans\n"); 10234e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare for (i = 0; i < 8; i++) { 10244e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare if (!(sio_data->has_fanin & (1 << i))) /* Not wired */ 10254e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare continue; 1026ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare pc87427_write8_bank(data, LD_FAN, BANK_FM(i), 1027ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare PC87427_REG_FAN_STATUS, 1028ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare FAN_STATUS_MONEN); 10294e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare } 10304e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare data->fan_enabled = sio_data->has_fanin; 1031ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare } 1032328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare 1033328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare /* Check which PWM outputs are enabled */ 1034328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare for (i = 0; i < 4; i++) { 1035328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare if (!(sio_data->has_fanout & (1 << i))) /* Not wired */ 1036328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare continue; 1037328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare reg = pc87427_read8_bank(data, LD_FAN, BANK_FC(i), 1038328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare PC87427_REG_PWM_ENABLE); 1039328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare if (reg & PWM_ENABLE_CTLEN) 1040328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare data->pwm_enabled |= (1 << i); 1041328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare 104236564efaddb7c1ace20f531860985a9848714c79Guenter Roeck /* 104336564efaddb7c1ace20f531860985a9848714c79Guenter Roeck * We don't expose an interface to reconfigure the automatic 104436564efaddb7c1ace20f531860985a9848714c79Guenter Roeck * fan control mode, so only allow to return to this mode if 104536564efaddb7c1ace20f531860985a9848714c79Guenter Roeck * it was originally set. 104636564efaddb7c1ace20f531860985a9848714c79Guenter Roeck */ 1047328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare if ((reg & PWM_ENABLE_MODE_MASK) == PWM_MODE_AUTO) { 1048328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare dev_dbg(dev, "PWM%d is in automatic control mode\n", 1049328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare i + 1); 1050328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare data->pwm_auto_ok |= (1 << i); 1051328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare } 1052328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare } 1053008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 1054008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare /* The HMC module should be ready */ 1055008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare reg = pc87427_read8(data, LD_TEMP, PC87427_REG_BANK); 1056008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare if (!(reg & 0x80)) 1057008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare dev_warn(dev, "%s module not ready!\n", "HMC"); 1058008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare 1059008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare /* Check which temperature channels are enabled */ 1060008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare for (i = 0; i < 6; i++) { 1061008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare reg = pc87427_read8_bank(data, LD_TEMP, BANK_TM(i), 1062008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare PC87427_REG_TEMP_STATUS); 1063008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare if (reg & TEMP_STATUS_CHANEN) 1064008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare data->temp_enabled |= (1 << i); 1065008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare } 1066ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare} 1067ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 1068c6b8724647eb1c24dc37cec8518bb6957f0000a8Jean Delvarestatic void pc87427_remove_files(struct device *dev) 1069c6b8724647eb1c24dc37cec8518bb6957f0000a8Jean Delvare{ 1070c6b8724647eb1c24dc37cec8518bb6957f0000a8Jean Delvare struct pc87427_data *data = dev_get_drvdata(dev); 1071c6b8724647eb1c24dc37cec8518bb6957f0000a8Jean Delvare int i; 1072c6b8724647eb1c24dc37cec8518bb6957f0000a8Jean Delvare 1073c6b8724647eb1c24dc37cec8518bb6957f0000a8Jean Delvare device_remove_file(dev, &dev_attr_name); 1074c6b8724647eb1c24dc37cec8518bb6957f0000a8Jean Delvare for (i = 0; i < 8; i++) { 1075c6b8724647eb1c24dc37cec8518bb6957f0000a8Jean Delvare if (!(data->fan_enabled & (1 << i))) 1076c6b8724647eb1c24dc37cec8518bb6957f0000a8Jean Delvare continue; 1077c6b8724647eb1c24dc37cec8518bb6957f0000a8Jean Delvare sysfs_remove_group(&dev->kobj, &pc87427_group_fan[i]); 1078c6b8724647eb1c24dc37cec8518bb6957f0000a8Jean Delvare } 1079c6b8724647eb1c24dc37cec8518bb6957f0000a8Jean Delvare for (i = 0; i < 4; i++) { 1080c6b8724647eb1c24dc37cec8518bb6957f0000a8Jean Delvare if (!(data->pwm_enabled & (1 << i))) 1081c6b8724647eb1c24dc37cec8518bb6957f0000a8Jean Delvare continue; 1082c6b8724647eb1c24dc37cec8518bb6957f0000a8Jean Delvare sysfs_remove_group(&dev->kobj, &pc87427_group_pwm[i]); 1083c6b8724647eb1c24dc37cec8518bb6957f0000a8Jean Delvare } 1084c6b8724647eb1c24dc37cec8518bb6957f0000a8Jean Delvare for (i = 0; i < 6; i++) { 1085c6b8724647eb1c24dc37cec8518bb6957f0000a8Jean Delvare if (!(data->temp_enabled & (1 << i))) 1086c6b8724647eb1c24dc37cec8518bb6957f0000a8Jean Delvare continue; 1087c6b8724647eb1c24dc37cec8518bb6957f0000a8Jean Delvare sysfs_remove_group(&dev->kobj, &pc87427_group_temp[i]); 1088c6b8724647eb1c24dc37cec8518bb6957f0000a8Jean Delvare } 1089c6b8724647eb1c24dc37cec8518bb6957f0000a8Jean Delvare} 1090c6b8724647eb1c24dc37cec8518bb6957f0000a8Jean Delvare 1091ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic int __devinit pc87427_probe(struct platform_device *pdev) 1092ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare{ 10939d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare struct pc87427_sio_data *sio_data = pdev->dev.platform_data; 1094ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare struct pc87427_data *data; 10959d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare int i, err, res_count; 1096ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 10970d22d5835d4c82d1d03399688267f63334efd526Jean Delvare data = kzalloc(sizeof(struct pc87427_data), GFP_KERNEL); 10980d22d5835d4c82d1d03399688267f63334efd526Jean Delvare if (!data) { 1099ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare err = -ENOMEM; 11005e24e0c365e0f83f9a6f5adb3bd0cf5ca5cd8ab1Joe Perches pr_err("Out of memory\n"); 1101ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare goto exit; 1102ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare } 1103ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 11049d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare data->address[0] = sio_data->address[0]; 11059d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare data->address[1] = sio_data->address[1]; 11069d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare res_count = (data->address[0] != 0) + (data->address[1] != 0); 11079d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare 11089d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare err = pc87427_request_regions(pdev, res_count); 11099d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare if (err) 1110ce7ee4e80a72d3b1009ca232be8981de93c015f6Jean Delvare goto exit_kfree; 1111ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 1112ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare mutex_init(&data->lock); 1113ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare data->name = "pc87427"; 1114ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare platform_set_drvdata(pdev, data); 1115ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare pc87427_init_device(&pdev->dev); 1116ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 1117ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare /* Register sysfs hooks */ 11180d22d5835d4c82d1d03399688267f63334efd526Jean Delvare err = device_create_file(&pdev->dev, &dev_attr_name); 11190d22d5835d4c82d1d03399688267f63334efd526Jean Delvare if (err) 1120ce7ee4e80a72d3b1009ca232be8981de93c015f6Jean Delvare goto exit_release_region; 1121ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare for (i = 0; i < 8; i++) { 1122ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare if (!(data->fan_enabled & (1 << i))) 1123ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare continue; 11240d22d5835d4c82d1d03399688267f63334efd526Jean Delvare err = sysfs_create_group(&pdev->dev.kobj, 11250d22d5835d4c82d1d03399688267f63334efd526Jean Delvare &pc87427_group_fan[i]); 11260d22d5835d4c82d1d03399688267f63334efd526Jean Delvare if (err) 1127ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare goto exit_remove_files; 1128ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare } 1129328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare for (i = 0; i < 4; i++) { 1130328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare if (!(data->pwm_enabled & (1 << i))) 1131328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare continue; 1132328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare err = sysfs_create_group(&pdev->dev.kobj, 1133328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare &pc87427_group_pwm[i]); 1134328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare if (err) 1135328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare goto exit_remove_files; 1136328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare } 1137008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare for (i = 0; i < 6; i++) { 1138008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare if (!(data->temp_enabled & (1 << i))) 1139008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare continue; 1140008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare err = sysfs_create_group(&pdev->dev.kobj, 1141008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare &pc87427_group_temp[i]); 1142008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare if (err) 1143008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare goto exit_remove_files; 1144008e5f3350e0a474baff3ed3eb4f79653a6b6745Jean Delvare } 1145ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 11461beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones data->hwmon_dev = hwmon_device_register(&pdev->dev); 11471beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones if (IS_ERR(data->hwmon_dev)) { 11481beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones err = PTR_ERR(data->hwmon_dev); 1149ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare dev_err(&pdev->dev, "Class registration failed (%d)\n", err); 1150ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare goto exit_remove_files; 1151ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare } 1152ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 1153ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare return 0; 1154ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 1155ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvareexit_remove_files: 1156c6b8724647eb1c24dc37cec8518bb6957f0000a8Jean Delvare pc87427_remove_files(&pdev->dev); 1157ce7ee4e80a72d3b1009ca232be8981de93c015f6Jean Delvareexit_release_region: 11589d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare pc87427_release_regions(pdev, res_count); 1159ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvareexit_kfree: 1160ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare platform_set_drvdata(pdev, NULL); 1161ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare kfree(data); 1162ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvareexit: 1163ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare return err; 1164ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare} 1165ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 1166ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic int __devexit pc87427_remove(struct platform_device *pdev) 1167ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare{ 1168ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare struct pc87427_data *data = platform_get_drvdata(pdev); 1169c6b8724647eb1c24dc37cec8518bb6957f0000a8Jean Delvare int res_count; 11709d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare 11719d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare res_count = (data->address[0] != 0) + (data->address[1] != 0); 1172ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 11731beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones hwmon_device_unregister(data->hwmon_dev); 1174c6b8724647eb1c24dc37cec8518bb6957f0000a8Jean Delvare pc87427_remove_files(&pdev->dev); 117504a6217df28e3004ba4e76eb0a356a30f72c564fJean Delvare platform_set_drvdata(pdev, NULL); 1176ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare kfree(data); 1177ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 11789d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare pc87427_release_regions(pdev, res_count); 1179ce7ee4e80a72d3b1009ca232be8981de93c015f6Jean Delvare 1180ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare return 0; 1181ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare} 1182ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 1183ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 1184ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic struct platform_driver pc87427_driver = { 1185ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare .driver = { 1186ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare .owner = THIS_MODULE, 1187ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare .name = DRVNAME, 1188ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare }, 1189ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare .probe = pc87427_probe, 1190ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare .remove = __devexit_p(pc87427_remove), 1191ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare}; 1192ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 11939d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvarestatic int __init pc87427_device_add(const struct pc87427_sio_data *sio_data) 1194ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare{ 11959d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare struct resource res[2] = { 11969d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare { .flags = IORESOURCE_IO }, 11979d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare { .flags = IORESOURCE_IO }, 1198ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare }; 11999d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare int err, i, res_count; 1200ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 12019d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare res_count = 0; 12029d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare for (i = 0; i < 2; i++) { 12039d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare if (!sio_data->address[i]) 12049d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare continue; 12059d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare res[res_count].start = sio_data->address[i]; 12069d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare res[res_count].end = sio_data->address[i] + REGION_LENGTH - 1; 12079d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare res[res_count].name = logdev_str[i]; 1208b9acb64a385c5b26fc392e0d58ac7b8e0a2cd812Jean Delvare 12099d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare err = acpi_check_resource_conflict(&res[res_count]); 12109d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare if (err) 12119d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare goto exit; 12129d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare 12139d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare res_count++; 12149d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare } 12159d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare 12169d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare pdev = platform_device_alloc(DRVNAME, res[0].start); 1217ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare if (!pdev) { 1218ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare err = -ENOMEM; 12195e24e0c365e0f83f9a6f5adb3bd0cf5ca5cd8ab1Joe Perches pr_err("Device allocation failed\n"); 1220ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare goto exit; 1221ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare } 1222ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 12239d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare err = platform_device_add_resources(pdev, res, res_count); 1224ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare if (err) { 12255e24e0c365e0f83f9a6f5adb3bd0cf5ca5cd8ab1Joe Perches pr_err("Device resource addition failed (%d)\n", err); 1226ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare goto exit_device_put; 1227ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare } 1228ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 12294e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare err = platform_device_add_data(pdev, sio_data, 12304e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare sizeof(struct pc87427_sio_data)); 12314e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare if (err) { 12325e24e0c365e0f83f9a6f5adb3bd0cf5ca5cd8ab1Joe Perches pr_err("Platform data allocation failed\n"); 12334e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare goto exit_device_put; 12344e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare } 12354e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare 1236ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare err = platform_device_add(pdev); 1237ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare if (err) { 12385e24e0c365e0f83f9a6f5adb3bd0cf5ca5cd8ab1Joe Perches pr_err("Device addition failed (%d)\n", err); 1239ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare goto exit_device_put; 1240ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare } 1241ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 1242ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare return 0; 1243ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 1244ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvareexit_device_put: 1245ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare platform_device_put(pdev); 1246ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvareexit: 1247ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare return err; 1248ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare} 1249ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 12509d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvarestatic int __init pc87427_find(int sioaddr, struct pc87427_sio_data *sio_data) 1251ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare{ 1252ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare u16 val; 12534e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare u8 cfg, cfg_b; 1254ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare int i, err = 0; 1255ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 1256ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare /* Identify device */ 125767b671bceb4a8340a30929e9642620d99ed5ad76Jean Delvare val = force_id ? force_id : superio_inb(sioaddr, SIOREG_DEVID); 1258ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare if (val != 0xf2) { /* PC87427 */ 1259ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare err = -ENODEV; 1260ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare goto exit; 1261ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare } 1262ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 1263ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare for (i = 0; i < 2; i++) { 12649d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare sio_data->address[i] = 0; 1265ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare /* Select logical device */ 1266ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare superio_outb(sioaddr, SIOREG_LDSEL, logdev[i]); 1267ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 1268ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare val = superio_inb(sioaddr, SIOREG_ACT); 1269ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare if (!(val & 0x01)) { 12705e24e0c365e0f83f9a6f5adb3bd0cf5ca5cd8ab1Joe Perches pr_info("Logical device 0x%02x not activated\n", 12715e24e0c365e0f83f9a6f5adb3bd0cf5ca5cd8ab1Joe Perches logdev[i]); 1272ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare continue; 1273ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare } 1274ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 1275ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare val = superio_inb(sioaddr, SIOREG_MAP); 1276ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare if (val & 0x01) { 12775e24e0c365e0f83f9a6f5adb3bd0cf5ca5cd8ab1Joe Perches pr_warn("Logical device 0x%02x is memory-mapped, " 12785e24e0c365e0f83f9a6f5adb3bd0cf5ca5cd8ab1Joe Perches "can't use\n", logdev[i]); 1279ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare continue; 1280ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare } 1281ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 1282ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare val = (superio_inb(sioaddr, SIOREG_IOBASE) << 8) 1283ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare | superio_inb(sioaddr, SIOREG_IOBASE + 1); 1284ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare if (!val) { 12855e24e0c365e0f83f9a6f5adb3bd0cf5ca5cd8ab1Joe Perches pr_info("I/O base address not set for logical device " 12865e24e0c365e0f83f9a6f5adb3bd0cf5ca5cd8ab1Joe Perches "0x%02x\n", logdev[i]); 1287ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare continue; 1288ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare } 12899d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare sio_data->address[i] = val; 12909d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare } 12919d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare 12929d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare /* No point in loading the driver if everything is disabled */ 12939d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare if (!sio_data->address[0] && !sio_data->address[1]) { 12949d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare err = -ENODEV; 12959d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare goto exit; 1296ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare } 1297ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 12984e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare /* Check which fan inputs are wired */ 12994e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare sio_data->has_fanin = (1 << 2) | (1 << 3); /* FANIN2, FANIN3 */ 13004e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare 13014e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare cfg = superio_inb(sioaddr, SIOREG_CF2); 13024e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare if (!(cfg & (1 << 3))) 13034e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare sio_data->has_fanin |= (1 << 0); /* FANIN0 */ 13044e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare if (!(cfg & (1 << 2))) 13054e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare sio_data->has_fanin |= (1 << 4); /* FANIN4 */ 13064e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare 13074e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare cfg = superio_inb(sioaddr, SIOREG_CFD); 13084e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare if (!(cfg & (1 << 0))) 13094e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare sio_data->has_fanin |= (1 << 1); /* FANIN1 */ 13104e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare 13114e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare cfg = superio_inb(sioaddr, SIOREG_CF4); 13124e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare if (!(cfg & (1 << 0))) 13134e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare sio_data->has_fanin |= (1 << 7); /* FANIN7 */ 13144e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare cfg_b = superio_inb(sioaddr, SIOREG_CFB); 13154e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare if (!(cfg & (1 << 1)) && (cfg_b & (1 << 3))) 13164e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare sio_data->has_fanin |= (1 << 5); /* FANIN5 */ 13174e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare cfg = superio_inb(sioaddr, SIOREG_CF3); 13184e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare if ((cfg & (1 << 3)) && !(cfg_b & (1 << 5))) 13194e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare sio_data->has_fanin |= (1 << 6); /* FANIN6 */ 13204e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare 1321328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare /* Check which fan outputs are wired */ 1322328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare sio_data->has_fanout = (1 << 0); /* FANOUT0 */ 1323328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare if (cfg_b & (1 << 0)) 1324328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare sio_data->has_fanout |= (1 << 3); /* FANOUT3 */ 1325328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare 1326328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare cfg = superio_inb(sioaddr, SIOREG_CFC); 1327328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare if (!(cfg & (1 << 4))) { 1328328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare if (cfg_b & (1 << 1)) 1329328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare sio_data->has_fanout |= (1 << 1); /* FANOUT1 */ 1330328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare if (cfg_b & (1 << 2)) 1331328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare sio_data->has_fanout |= (1 << 2); /* FANOUT2 */ 1332328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare } 1333328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare 1334328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare /* FANOUT1 and FANOUT2 can each be routed to 2 different pins */ 1335328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare cfg = superio_inb(sioaddr, SIOREG_CF5); 1336328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare if (cfg & (1 << 6)) 1337328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare sio_data->has_fanout |= (1 << 1); /* FANOUT1 */ 1338328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare if (cfg & (1 << 5)) 1339328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare sio_data->has_fanout |= (1 << 2); /* FANOUT2 */ 1340328716bc16b7077ea5f6293c7420247c570d6480Jean Delvare 1341ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvareexit: 1342ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare superio_exit(sioaddr); 1343ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare return err; 1344ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare} 1345ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 1346ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic int __init pc87427_init(void) 1347ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare{ 1348ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare int err; 13494e7d99e1acddea44be61aee0b934a7ce45d4c3f4Jean Delvare struct pc87427_sio_data sio_data; 1350ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 13519d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare if (pc87427_find(0x2e, &sio_data) 13529d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare && pc87427_find(0x4e, &sio_data)) 1353ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare return -ENODEV; 1354ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 1355ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare err = platform_driver_register(&pc87427_driver); 1356ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare if (err) 1357ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare goto exit; 1358ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 1359ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare /* Sets global pdev as a side effect */ 13609d32df192d2e4db4d59f26a3ea73601bd1a733e5Jean Delvare err = pc87427_device_add(&sio_data); 1361ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare if (err) 1362ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare goto exit_driver; 1363ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 1364ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare return 0; 1365ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 1366ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvareexit_driver: 1367ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare platform_driver_unregister(&pc87427_driver); 1368ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvareexit: 1369ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare return err; 1370ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare} 1371ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 1372ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvarestatic void __exit pc87427_exit(void) 1373ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare{ 1374ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare platform_device_unregister(pdev); 1375ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare platform_driver_unregister(&pc87427_driver); 1376ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare} 1377ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 1378ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean DelvareMODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>"); 1379ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean DelvareMODULE_DESCRIPTION("PC87427 hardware monitoring driver"); 1380ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean DelvareMODULE_LICENSE("GPL"); 1381ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvare 1382ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvaremodule_init(pc87427_init); 1383ba224e2c4f0a706714ccb483b0c21d32f5994f67Jean Delvaremodule_exit(pc87427_exit); 1384