1b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj/* 2ca3c7b63423c7f723258797bcb5b11652d32500bGuenter Roeck * amc6821.c - Part of lm_sensors, Linux kernel modules for hardware 3ca3c7b63423c7f723258797bcb5b11652d32500bGuenter Roeck * monitoring 4ca3c7b63423c7f723258797bcb5b11652d32500bGuenter Roeck * Copyright (C) 2009 T. Mertelj <tomaz.mertelj@guest.arnes.si> 5ca3c7b63423c7f723258797bcb5b11652d32500bGuenter Roeck * 6ca3c7b63423c7f723258797bcb5b11652d32500bGuenter Roeck * Based on max6650.c: 7ca3c7b63423c7f723258797bcb5b11652d32500bGuenter Roeck * Copyright (C) 2007 Hans J. Koch <hjk@hansjkoch.de> 8ca3c7b63423c7f723258797bcb5b11652d32500bGuenter Roeck * 9ca3c7b63423c7f723258797bcb5b11652d32500bGuenter Roeck * This program is free software; you can redistribute it and/or modify 10ca3c7b63423c7f723258797bcb5b11652d32500bGuenter Roeck * it under the terms of the GNU General Public License as published by 11ca3c7b63423c7f723258797bcb5b11652d32500bGuenter Roeck * the Free Software Foundation; either version 2 of the License, or 12ca3c7b63423c7f723258797bcb5b11652d32500bGuenter Roeck * (at your option) any later version. 13ca3c7b63423c7f723258797bcb5b11652d32500bGuenter Roeck * 14ca3c7b63423c7f723258797bcb5b11652d32500bGuenter Roeck * This program is distributed in the hope that it will be useful, 15ca3c7b63423c7f723258797bcb5b11652d32500bGuenter Roeck * but WITHOUT ANY WARRANTY; without even the implied warranty of 16ca3c7b63423c7f723258797bcb5b11652d32500bGuenter Roeck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17ca3c7b63423c7f723258797bcb5b11652d32500bGuenter Roeck * GNU General Public License for more details. 18ca3c7b63423c7f723258797bcb5b11652d32500bGuenter Roeck * 19ca3c7b63423c7f723258797bcb5b11652d32500bGuenter Roeck * You should have received a copy of the GNU General Public License 20ca3c7b63423c7f723258797bcb5b11652d32500bGuenter Roeck * along with this program; if not, write to the Free Software 21ca3c7b63423c7f723258797bcb5b11652d32500bGuenter Roeck * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 22ca3c7b63423c7f723258797bcb5b11652d32500bGuenter Roeck */ 23b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 24b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#include <linux/kernel.h> /* Needed for KERN_INFO */ 25b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#include <linux/module.h> 26b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#include <linux/init.h> 27b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#include <linux/slab.h> 28b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#include <linux/jiffies.h> 29b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#include <linux/i2c.h> 30b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#include <linux/hwmon.h> 31b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#include <linux/hwmon-sysfs.h> 32b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#include <linux/err.h> 33b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#include <linux/mutex.h> 34b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 35b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj/* 36b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj * Addresses to scan. 37b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj */ 38b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 39b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic const unsigned short normal_i2c[] = {0x18, 0x19, 0x1a, 0x2c, 0x2d, 0x2e, 40b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 0x4c, 0x4d, 0x4e, I2C_CLIENT_END}; 41b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 42b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj/* 43b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj * Insmod parameters 44b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj */ 45b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 46a6bee4a5571d24b9ba7c98f6becc7c45312a537dFrans Meulenbroeksstatic int pwminv; /*Inverted PWM output. */ 47b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljmodule_param(pwminv, int, S_IRUGO); 48b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 49b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic int init = 1; /*Power-on initialization.*/ 50b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljmodule_param(init, int, S_IRUGO); 51b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 52b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljenum chips { amc6821 }; 53b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 54b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_DEV_ID 0x3D 55b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_COMP_ID 0x3E 56b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_CONF1 0x00 57b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_CONF2 0x01 58b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_CONF3 0x3F 59b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_CONF4 0x04 60b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_STAT1 0x02 61b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_STAT2 0x03 62b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_TDATA_LOW 0x08 63b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_TDATA_HI 0x09 64b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_LTEMP_HI 0x0A 65b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_RTEMP_HI 0x0B 66b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_LTEMP_LIMIT_MIN 0x15 67b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_LTEMP_LIMIT_MAX 0x14 68b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_RTEMP_LIMIT_MIN 0x19 69b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_RTEMP_LIMIT_MAX 0x18 70b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_LTEMP_CRIT 0x1B 71b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_RTEMP_CRIT 0x1D 72b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_PSV_TEMP 0x1C 73b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_DCY 0x22 74b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_LTEMP_FAN_CTRL 0x24 75b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_RTEMP_FAN_CTRL 0x25 76b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_DCY_LOW_TEMP 0x21 77b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 78b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_TACH_LLIMITL 0x10 79b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_TACH_LLIMITH 0x11 80b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_TACH_HLIMITL 0x12 81b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_REG_TACH_HLIMITH 0x13 82b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 83b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF1_START 0x01 84b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF1_FAN_INT_EN 0x02 85b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF1_FANIE 0x04 86b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF1_PWMINV 0x08 87b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF1_FAN_FAULT_EN 0x10 88b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF1_FDRC0 0x20 89b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF1_FDRC1 0x40 90b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF1_THERMOVIE 0x80 91b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 92b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF2_PWM_EN 0x01 93b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF2_TACH_MODE 0x02 94b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF2_TACH_EN 0x04 95b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF2_RTFIE 0x08 96b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF2_LTOIE 0x10 97b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF2_RTOIE 0x20 98b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF2_PSVIE 0x40 99b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF2_RST 0x80 100b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 101b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF3_THERM_FAN_EN 0x80 102b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF3_REV_MASK 0x0F 103b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 104b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF4_OVREN 0x10 105b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF4_TACH_FAST 0x20 106b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF4_PSPR 0x40 107b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_CONF4_MODE 0x80 108b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 109b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_STAT1_RPM_ALARM 0x01 110b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_STAT1_FANS 0x02 111b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_STAT1_RTH 0x04 112b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_STAT1_RTL 0x08 113b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_STAT1_R_THERM 0x10 114b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_STAT1_RTF 0x20 115b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_STAT1_LTH 0x40 116b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_STAT1_LTL 0x80 117b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 118b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_STAT2_RTC 0x08 119b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_STAT2_LTC 0x10 120b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_STAT2_LPSV 0x20 121b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_STAT2_L_THERM 0x40 122b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj#define AMC6821_STAT2_THERM_IN 0x80 123b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 124b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljenum {IDX_TEMP1_INPUT = 0, IDX_TEMP1_MIN, IDX_TEMP1_MAX, 125b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj IDX_TEMP1_CRIT, IDX_TEMP2_INPUT, IDX_TEMP2_MIN, 126b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj IDX_TEMP2_MAX, IDX_TEMP2_CRIT, 127b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj TEMP_IDX_LEN, }; 128b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 129b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic const u8 temp_reg[] = {AMC6821_REG_LTEMP_HI, 130b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj AMC6821_REG_LTEMP_LIMIT_MIN, 131b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj AMC6821_REG_LTEMP_LIMIT_MAX, 132b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj AMC6821_REG_LTEMP_CRIT, 133b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj AMC6821_REG_RTEMP_HI, 134b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj AMC6821_REG_RTEMP_LIMIT_MIN, 135b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj AMC6821_REG_RTEMP_LIMIT_MAX, 136b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj AMC6821_REG_RTEMP_CRIT, }; 137b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 138b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljenum {IDX_FAN1_INPUT = 0, IDX_FAN1_MIN, IDX_FAN1_MAX, 139b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj FAN1_IDX_LEN, }; 140b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 141b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic const u8 fan_reg_low[] = {AMC6821_REG_TDATA_LOW, 142b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj AMC6821_REG_TACH_LLIMITL, 143b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj AMC6821_REG_TACH_HLIMITL, }; 144b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 145b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 146b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic const u8 fan_reg_hi[] = {AMC6821_REG_TDATA_HI, 147b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj AMC6821_REG_TACH_LLIMITH, 148b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj AMC6821_REG_TACH_HLIMITH, }; 149b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 150b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj/* 151b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj * Client data (each client gets its own) 152ca3c7b63423c7f723258797bcb5b11652d32500bGuenter Roeck */ 153b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 154b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstruct amc6821_data { 1551276fae2a93142525580d6f6ab77105f4d7a0e09Axel Lin struct i2c_client *client; 156b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct mutex update_lock; 157b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj char valid; /* zero until following fields are valid */ 158b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj unsigned long last_updated; /* in jiffies */ 159b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 160b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj /* register values */ 161b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj int temp[TEMP_IDX_LEN]; 162b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 163b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj u16 fan[FAN1_IDX_LEN]; 164b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj u8 fan1_div; 165b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 166b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj u8 pwm1; 167b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj u8 temp1_auto_point_temp[3]; 168b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj u8 temp2_auto_point_temp[3]; 169b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj u8 pwm1_auto_point_pwm[3]; 170b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj u8 pwm1_enable; 171b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj u8 pwm1_auto_channels_temp; 172b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 173b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj u8 stat1; 174b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj u8 stat2; 175b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj}; 176b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 17728e6274d8fa67ecb468eaa219c45595384e3bda8Axel Linstatic struct amc6821_data *amc6821_update_device(struct device *dev) 17828e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin{ 1791276fae2a93142525580d6f6ab77105f4d7a0e09Axel Lin struct amc6821_data *data = dev_get_drvdata(dev); 1801276fae2a93142525580d6f6ab77105f4d7a0e09Axel Lin struct i2c_client *client = data->client; 18128e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin int timeout = HZ; 18228e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin u8 reg; 18328e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin int i; 18428e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin 18528e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin mutex_lock(&data->update_lock); 18628e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin 18728e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin if (time_after(jiffies, data->last_updated + timeout) || 18828e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin !data->valid) { 18928e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin 19028e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin for (i = 0; i < TEMP_IDX_LEN; i++) 19128e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin data->temp[i] = i2c_smbus_read_byte_data(client, 19228e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin temp_reg[i]); 19328e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin 19428e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin data->stat1 = i2c_smbus_read_byte_data(client, 19528e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin AMC6821_REG_STAT1); 19628e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin data->stat2 = i2c_smbus_read_byte_data(client, 19728e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin AMC6821_REG_STAT2); 19828e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin 19928e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin data->pwm1 = i2c_smbus_read_byte_data(client, 20028e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin AMC6821_REG_DCY); 20128e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin for (i = 0; i < FAN1_IDX_LEN; i++) { 20228e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin data->fan[i] = i2c_smbus_read_byte_data( 20328e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin client, 20428e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin fan_reg_low[i]); 20528e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin data->fan[i] += i2c_smbus_read_byte_data( 20628e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin client, 20728e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin fan_reg_hi[i]) << 8; 20828e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin } 20928e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin data->fan1_div = i2c_smbus_read_byte_data(client, 21028e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin AMC6821_REG_CONF4); 21128e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin data->fan1_div = data->fan1_div & AMC6821_CONF4_PSPR ? 4 : 2; 21228e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin 21328e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin data->pwm1_auto_point_pwm[0] = 0; 21428e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin data->pwm1_auto_point_pwm[2] = 255; 21528e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin data->pwm1_auto_point_pwm[1] = i2c_smbus_read_byte_data(client, 21628e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin AMC6821_REG_DCY_LOW_TEMP); 21728e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin 21828e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin data->temp1_auto_point_temp[0] = 21928e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin i2c_smbus_read_byte_data(client, 22028e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin AMC6821_REG_PSV_TEMP); 22128e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin data->temp2_auto_point_temp[0] = 22228e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin data->temp1_auto_point_temp[0]; 22328e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin reg = i2c_smbus_read_byte_data(client, 22428e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin AMC6821_REG_LTEMP_FAN_CTRL); 22528e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin data->temp1_auto_point_temp[1] = (reg & 0xF8) >> 1; 22628e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin reg &= 0x07; 22728e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin reg = 0x20 >> reg; 22828e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin if (reg > 0) 22928e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin data->temp1_auto_point_temp[2] = 23028e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin data->temp1_auto_point_temp[1] + 23128e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin (data->pwm1_auto_point_pwm[2] - 23228e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin data->pwm1_auto_point_pwm[1]) / reg; 23328e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin else 23428e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin data->temp1_auto_point_temp[2] = 255; 23528e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin 23628e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin reg = i2c_smbus_read_byte_data(client, 23728e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin AMC6821_REG_RTEMP_FAN_CTRL); 23828e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin data->temp2_auto_point_temp[1] = (reg & 0xF8) >> 1; 23928e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin reg &= 0x07; 24028e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin reg = 0x20 >> reg; 24128e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin if (reg > 0) 24228e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin data->temp2_auto_point_temp[2] = 24328e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin data->temp2_auto_point_temp[1] + 24428e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin (data->pwm1_auto_point_pwm[2] - 24528e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin data->pwm1_auto_point_pwm[1]) / reg; 24628e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin else 24728e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin data->temp2_auto_point_temp[2] = 255; 24828e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin 24928e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin reg = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF1); 25028e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin reg = (reg >> 5) & 0x3; 25128e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin switch (reg) { 25228e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin case 0: /*open loop: software sets pwm1*/ 25328e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin data->pwm1_auto_channels_temp = 0; 25428e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin data->pwm1_enable = 1; 25528e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin break; 25628e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin case 2: /*closed loop: remote T (temp2)*/ 25728e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin data->pwm1_auto_channels_temp = 2; 25828e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin data->pwm1_enable = 2; 25928e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin break; 26028e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin case 3: /*closed loop: local and remote T (temp2)*/ 26128e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin data->pwm1_auto_channels_temp = 3; 26228e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin data->pwm1_enable = 3; 26328e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin break; 26428e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin case 1: /* 26528e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin * semi-open loop: software sets rpm, chip controls 26628e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin * pwm1, currently not implemented 26728e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin */ 26828e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin data->pwm1_auto_channels_temp = 0; 26928e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin data->pwm1_enable = 0; 27028e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin break; 27128e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin } 27228e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin 27328e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin data->last_updated = jiffies; 27428e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin data->valid = 1; 27528e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin } 27628e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin mutex_unlock(&data->update_lock); 27728e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin return data; 27828e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin} 279b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 280b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t get_temp( 281b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device *dev, 282b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device_attribute *devattr, 283b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj char *buf) 284b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{ 285b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct amc6821_data *data = amc6821_update_device(dev); 286b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj int ix = to_sensor_dev_attr(devattr)->index; 287b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 288b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return sprintf(buf, "%d\n", data->temp[ix] * 1000); 289b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj} 290b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 291b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t set_temp( 292b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device *dev, 293b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device_attribute *attr, 294b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj const char *buf, 295b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj size_t count) 296b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{ 2971276fae2a93142525580d6f6ab77105f4d7a0e09Axel Lin struct amc6821_data *data = dev_get_drvdata(dev); 2981276fae2a93142525580d6f6ab77105f4d7a0e09Axel Lin struct i2c_client *client = data->client; 299b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj int ix = to_sensor_dev_attr(attr)->index; 300b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj long val; 301b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 302179c4fdb565dd2157e5dfe89318b74868e3b523dFrans Meulenbroeks int ret = kstrtol(buf, 10, &val); 303b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (ret) 304b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return ret; 3052a844c148e1f714ebf42cb96e1b172ce394c36c9Guenter Roeck val = clamp_val(val / 1000, -128, 127); 306b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 307b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj mutex_lock(&data->update_lock); 308b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj data->temp[ix] = val; 309b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (i2c_smbus_write_byte_data(client, temp_reg[ix], data->temp[ix])) { 310b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj dev_err(&client->dev, "Register write error, aborting.\n"); 311b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj count = -EIO; 312b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj } 313b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj mutex_unlock(&data->update_lock); 314b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return count; 315b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj} 316b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 317b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t get_temp_alarm( 318b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device *dev, 319b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device_attribute *devattr, 320b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj char *buf) 321b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{ 322b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct amc6821_data *data = amc6821_update_device(dev); 323b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj int ix = to_sensor_dev_attr(devattr)->index; 324b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj u8 flag; 325b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 326b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj switch (ix) { 327b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj case IDX_TEMP1_MIN: 328b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj flag = data->stat1 & AMC6821_STAT1_LTL; 329b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj break; 330b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj case IDX_TEMP1_MAX: 331b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj flag = data->stat1 & AMC6821_STAT1_LTH; 332b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj break; 333b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj case IDX_TEMP1_CRIT: 334b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj flag = data->stat2 & AMC6821_STAT2_LTC; 335b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj break; 336b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj case IDX_TEMP2_MIN: 337b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj flag = data->stat1 & AMC6821_STAT1_RTL; 338b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj break; 339b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj case IDX_TEMP2_MAX: 340b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj flag = data->stat1 & AMC6821_STAT1_RTH; 341b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj break; 342b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj case IDX_TEMP2_CRIT: 343b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj flag = data->stat2 & AMC6821_STAT2_RTC; 344b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj break; 345b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj default: 346b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj dev_dbg(dev, "Unknown attr->index (%d).\n", ix); 347b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return -EINVAL; 348b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj } 349b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (flag) 350b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return sprintf(buf, "1"); 351b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj else 352b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return sprintf(buf, "0"); 353b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj} 354b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 355b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t get_temp2_fault( 356b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device *dev, 357b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device_attribute *devattr, 358b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj char *buf) 359b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{ 360b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct amc6821_data *data = amc6821_update_device(dev); 361b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (data->stat1 & AMC6821_STAT1_RTF) 362b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return sprintf(buf, "1"); 363b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj else 364b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return sprintf(buf, "0"); 365b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj} 366b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 367b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t get_pwm1( 368b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device *dev, 369b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device_attribute *devattr, 370b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj char *buf) 371b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{ 372b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct amc6821_data *data = amc6821_update_device(dev); 373b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return sprintf(buf, "%d\n", data->pwm1); 374b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj} 375b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 376b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t set_pwm1( 377b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device *dev, 378b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device_attribute *devattr, 379b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj const char *buf, 380b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj size_t count) 381b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{ 3821276fae2a93142525580d6f6ab77105f4d7a0e09Axel Lin struct amc6821_data *data = dev_get_drvdata(dev); 3831276fae2a93142525580d6f6ab77105f4d7a0e09Axel Lin struct i2c_client *client = data->client; 384b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj long val; 385179c4fdb565dd2157e5dfe89318b74868e3b523dFrans Meulenbroeks int ret = kstrtol(buf, 10, &val); 386b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (ret) 387b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return ret; 388b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 389b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj mutex_lock(&data->update_lock); 3902a844c148e1f714ebf42cb96e1b172ce394c36c9Guenter Roeck data->pwm1 = clamp_val(val , 0, 255); 391b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj i2c_smbus_write_byte_data(client, AMC6821_REG_DCY, data->pwm1); 392b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj mutex_unlock(&data->update_lock); 393b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return count; 394b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj} 395b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 396b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t get_pwm1_enable( 397b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device *dev, 398b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device_attribute *devattr, 399b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj char *buf) 400b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{ 401b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct amc6821_data *data = amc6821_update_device(dev); 402b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return sprintf(buf, "%d\n", data->pwm1_enable); 403b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj} 404b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 405b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t set_pwm1_enable( 406b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device *dev, 407b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device_attribute *attr, 408b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj const char *buf, 409b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj size_t count) 410b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{ 4111276fae2a93142525580d6f6ab77105f4d7a0e09Axel Lin struct amc6821_data *data = dev_get_drvdata(dev); 4121276fae2a93142525580d6f6ab77105f4d7a0e09Axel Lin struct i2c_client *client = data->client; 413b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj long val; 414179c4fdb565dd2157e5dfe89318b74868e3b523dFrans Meulenbroeks int config = kstrtol(buf, 10, &val); 415b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (config) 416b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return config; 417b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 418cf44819c98db11163f58f08b822d626c7a8f5188Axel Lin mutex_lock(&data->update_lock); 419b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF1); 420b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (config < 0) { 421b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj dev_err(&client->dev, 422b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj "Error reading configuration register, aborting.\n"); 423cf44819c98db11163f58f08b822d626c7a8f5188Axel Lin count = config; 424cf44819c98db11163f58f08b822d626c7a8f5188Axel Lin goto unlock; 425b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj } 426b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 427b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj switch (val) { 428b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj case 1: 429b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj config &= ~AMC6821_CONF1_FDRC0; 430b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj config &= ~AMC6821_CONF1_FDRC1; 431b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj break; 432b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj case 2: 433b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj config &= ~AMC6821_CONF1_FDRC0; 434b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj config |= AMC6821_CONF1_FDRC1; 435b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj break; 436b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj case 3: 437b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj config |= AMC6821_CONF1_FDRC0; 438b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj config |= AMC6821_CONF1_FDRC1; 439b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj break; 440b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj default: 441cf44819c98db11163f58f08b822d626c7a8f5188Axel Lin count = -EINVAL; 442cf44819c98db11163f58f08b822d626c7a8f5188Axel Lin goto unlock; 443b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj } 444b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (i2c_smbus_write_byte_data(client, AMC6821_REG_CONF1, config)) { 445b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj dev_err(&client->dev, 446b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj "Configuration register write error, aborting.\n"); 447b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj count = -EIO; 448b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj } 449cf44819c98db11163f58f08b822d626c7a8f5188Axel Linunlock: 450b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj mutex_unlock(&data->update_lock); 451b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return count; 452b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj} 453b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 454b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t get_pwm1_auto_channels_temp( 455b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device *dev, 456b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device_attribute *devattr, 457b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj char *buf) 458b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{ 459b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct amc6821_data *data = amc6821_update_device(dev); 460b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return sprintf(buf, "%d\n", data->pwm1_auto_channels_temp); 461b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj} 462b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 463b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t get_temp_auto_point_temp( 464b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device *dev, 465b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device_attribute *devattr, 466b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj char *buf) 467b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{ 468b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj int ix = to_sensor_dev_attr_2(devattr)->index; 469b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj int nr = to_sensor_dev_attr_2(devattr)->nr; 470b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct amc6821_data *data = amc6821_update_device(dev); 471b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj switch (nr) { 472b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj case 1: 473b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return sprintf(buf, "%d\n", 474b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj data->temp1_auto_point_temp[ix] * 1000); 475b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj case 2: 476b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return sprintf(buf, "%d\n", 477b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj data->temp2_auto_point_temp[ix] * 1000); 478b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj default: 479b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj dev_dbg(dev, "Unknown attr->nr (%d).\n", nr); 480b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return -EINVAL; 481b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj } 482b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj} 483b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 484b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t get_pwm1_auto_point_pwm( 485b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device *dev, 486b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device_attribute *devattr, 487b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj char *buf) 488b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{ 489b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj int ix = to_sensor_dev_attr(devattr)->index; 490b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct amc6821_data *data = amc6821_update_device(dev); 491b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return sprintf(buf, "%d\n", data->pwm1_auto_point_pwm[ix]); 492b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj} 493b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 494b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic inline ssize_t set_slope_register(struct i2c_client *client, 495b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj u8 reg, 496b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj u8 dpwm, 497b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj u8 *ptemp) 498b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{ 499b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj int dt; 500b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj u8 tmp; 501b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 502b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj dt = ptemp[2]-ptemp[1]; 503b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj for (tmp = 4; tmp > 0; tmp--) { 504b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (dt * (0x20 >> tmp) >= dpwm) 505b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj break; 506b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj } 507b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj tmp |= (ptemp[1] & 0x7C) << 1; 508b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (i2c_smbus_write_byte_data(client, 509b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj reg, tmp)) { 510b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj dev_err(&client->dev, "Register write error, aborting.\n"); 511b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return -EIO; 512b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj } 513b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return 0; 514b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj} 515b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 516b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t set_temp_auto_point_temp( 517b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device *dev, 518b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device_attribute *attr, 519b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj const char *buf, 520b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj size_t count) 521b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{ 522b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct amc6821_data *data = amc6821_update_device(dev); 5231276fae2a93142525580d6f6ab77105f4d7a0e09Axel Lin struct i2c_client *client = data->client; 524b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj int ix = to_sensor_dev_attr_2(attr)->index; 525b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj int nr = to_sensor_dev_attr_2(attr)->nr; 526b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj u8 *ptemp; 527b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj u8 reg; 528b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj int dpwm; 529b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj long val; 530179c4fdb565dd2157e5dfe89318b74868e3b523dFrans Meulenbroeks int ret = kstrtol(buf, 10, &val); 531b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (ret) 532b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return ret; 533b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 534b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj switch (nr) { 535b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj case 1: 536b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj ptemp = data->temp1_auto_point_temp; 537b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj reg = AMC6821_REG_LTEMP_FAN_CTRL; 538b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj break; 539b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj case 2: 540b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj ptemp = data->temp2_auto_point_temp; 541b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj reg = AMC6821_REG_RTEMP_FAN_CTRL; 542b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj break; 543b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj default: 544b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj dev_dbg(dev, "Unknown attr->nr (%d).\n", nr); 545b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return -EINVAL; 546b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj } 547b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 548b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj mutex_lock(&data->update_lock); 549cf44819c98db11163f58f08b822d626c7a8f5188Axel Lin data->valid = 0; 550cf44819c98db11163f58f08b822d626c7a8f5188Axel Lin 551b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj switch (ix) { 552b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj case 0: 5532a844c148e1f714ebf42cb96e1b172ce394c36c9Guenter Roeck ptemp[0] = clamp_val(val / 1000, 0, 5542a844c148e1f714ebf42cb96e1b172ce394c36c9Guenter Roeck data->temp1_auto_point_temp[1]); 5552a844c148e1f714ebf42cb96e1b172ce394c36c9Guenter Roeck ptemp[0] = clamp_val(ptemp[0], 0, 5562a844c148e1f714ebf42cb96e1b172ce394c36c9Guenter Roeck data->temp2_auto_point_temp[1]); 5572a844c148e1f714ebf42cb96e1b172ce394c36c9Guenter Roeck ptemp[0] = clamp_val(ptemp[0], 0, 63); 558b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (i2c_smbus_write_byte_data( 559b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj client, 560b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj AMC6821_REG_PSV_TEMP, 561b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj ptemp[0])) { 562b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj dev_err(&client->dev, 563b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj "Register write error, aborting.\n"); 564b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj count = -EIO; 565b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj } 566b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj goto EXIT; 567b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj case 1: 5682a844c148e1f714ebf42cb96e1b172ce394c36c9Guenter Roeck ptemp[1] = clamp_val(val / 1000, (ptemp[0] & 0x7C) + 4, 124); 569b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj ptemp[1] &= 0x7C; 5702a844c148e1f714ebf42cb96e1b172ce394c36c9Guenter Roeck ptemp[2] = clamp_val(ptemp[2], ptemp[1] + 1, 255); 571b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj break; 572b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj case 2: 5732a844c148e1f714ebf42cb96e1b172ce394c36c9Guenter Roeck ptemp[2] = clamp_val(val / 1000, ptemp[1]+1, 255); 574b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj break; 575b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj default: 576b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj dev_dbg(dev, "Unknown attr->index (%d).\n", ix); 577b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj count = -EINVAL; 578b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj goto EXIT; 579b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj } 580b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj dpwm = data->pwm1_auto_point_pwm[2] - data->pwm1_auto_point_pwm[1]; 581b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (set_slope_register(client, reg, dpwm, ptemp)) 582b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj count = -EIO; 583b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 584b5430a04e995081a308b4419bd0940f2badc6e6bTomaz MerteljEXIT: 585b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj mutex_unlock(&data->update_lock); 586b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return count; 587b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj} 588b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 589b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t set_pwm1_auto_point_pwm( 590b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device *dev, 591b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device_attribute *attr, 592b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj const char *buf, 593b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj size_t count) 594b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{ 5951276fae2a93142525580d6f6ab77105f4d7a0e09Axel Lin struct amc6821_data *data = dev_get_drvdata(dev); 5961276fae2a93142525580d6f6ab77105f4d7a0e09Axel Lin struct i2c_client *client = data->client; 597b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj int dpwm; 598b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj long val; 599179c4fdb565dd2157e5dfe89318b74868e3b523dFrans Meulenbroeks int ret = kstrtol(buf, 10, &val); 600b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (ret) 601b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return ret; 602b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 603b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj mutex_lock(&data->update_lock); 6042a844c148e1f714ebf42cb96e1b172ce394c36c9Guenter Roeck data->pwm1_auto_point_pwm[1] = clamp_val(val, 0, 254); 605b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (i2c_smbus_write_byte_data(client, AMC6821_REG_DCY_LOW_TEMP, 606b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj data->pwm1_auto_point_pwm[1])) { 607b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj dev_err(&client->dev, "Register write error, aborting.\n"); 608b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj count = -EIO; 609b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj goto EXIT; 610b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj } 611b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj dpwm = data->pwm1_auto_point_pwm[2] - data->pwm1_auto_point_pwm[1]; 612b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (set_slope_register(client, AMC6821_REG_LTEMP_FAN_CTRL, dpwm, 613b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj data->temp1_auto_point_temp)) { 614b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj count = -EIO; 615b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj goto EXIT; 616b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj } 617b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (set_slope_register(client, AMC6821_REG_RTEMP_FAN_CTRL, dpwm, 618b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj data->temp2_auto_point_temp)) { 619b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj count = -EIO; 620b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj goto EXIT; 621b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj } 622b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 623b5430a04e995081a308b4419bd0940f2badc6e6bTomaz MerteljEXIT: 624b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj data->valid = 0; 625b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj mutex_unlock(&data->update_lock); 626b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return count; 627b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj} 628b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 629b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t get_fan( 630b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device *dev, 631b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device_attribute *devattr, 632b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj char *buf) 633b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{ 634b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct amc6821_data *data = amc6821_update_device(dev); 635b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj int ix = to_sensor_dev_attr(devattr)->index; 636b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (0 == data->fan[ix]) 637b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return sprintf(buf, "0"); 638b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return sprintf(buf, "%d\n", (int)(6000000 / data->fan[ix])); 639b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj} 640b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 641b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t get_fan1_fault( 642b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device *dev, 643b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device_attribute *devattr, 644b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj char *buf) 645b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{ 646b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct amc6821_data *data = amc6821_update_device(dev); 647b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (data->stat1 & AMC6821_STAT1_FANS) 648b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return sprintf(buf, "1"); 649b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj else 650b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return sprintf(buf, "0"); 651b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj} 652b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 653b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t set_fan( 654b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device *dev, 655b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device_attribute *attr, 656b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj const char *buf, size_t count) 657b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{ 6581276fae2a93142525580d6f6ab77105f4d7a0e09Axel Lin struct amc6821_data *data = dev_get_drvdata(dev); 6591276fae2a93142525580d6f6ab77105f4d7a0e09Axel Lin struct i2c_client *client = data->client; 660b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj long val; 661b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj int ix = to_sensor_dev_attr(attr)->index; 662179c4fdb565dd2157e5dfe89318b74868e3b523dFrans Meulenbroeks int ret = kstrtol(buf, 10, &val); 663b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (ret) 664b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return ret; 665b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj val = 1 > val ? 0xFFFF : 6000000/val; 666b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 667b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj mutex_lock(&data->update_lock); 6682a844c148e1f714ebf42cb96e1b172ce394c36c9Guenter Roeck data->fan[ix] = (u16) clamp_val(val, 1, 0xFFFF); 669b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (i2c_smbus_write_byte_data(client, fan_reg_low[ix], 670b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj data->fan[ix] & 0xFF)) { 671b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj dev_err(&client->dev, "Register write error, aborting.\n"); 672b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj count = -EIO; 673b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj goto EXIT; 674b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj } 675b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (i2c_smbus_write_byte_data(client, 676b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj fan_reg_hi[ix], data->fan[ix] >> 8)) { 677b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj dev_err(&client->dev, "Register write error, aborting.\n"); 678b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj count = -EIO; 679b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj } 680b5430a04e995081a308b4419bd0940f2badc6e6bTomaz MerteljEXIT: 681b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj mutex_unlock(&data->update_lock); 682b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return count; 683b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj} 684b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 685b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t get_fan1_div( 686b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device *dev, 687b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device_attribute *devattr, 688b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj char *buf) 689b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{ 690b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct amc6821_data *data = amc6821_update_device(dev); 691b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return sprintf(buf, "%d\n", data->fan1_div); 692b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj} 693b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 694b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic ssize_t set_fan1_div( 695b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device *dev, 696b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct device_attribute *attr, 697b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj const char *buf, size_t count) 698b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{ 6991276fae2a93142525580d6f6ab77105f4d7a0e09Axel Lin struct amc6821_data *data = dev_get_drvdata(dev); 7001276fae2a93142525580d6f6ab77105f4d7a0e09Axel Lin struct i2c_client *client = data->client; 701b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj long val; 702179c4fdb565dd2157e5dfe89318b74868e3b523dFrans Meulenbroeks int config = kstrtol(buf, 10, &val); 703b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (config) 704b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return config; 705b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 706cf44819c98db11163f58f08b822d626c7a8f5188Axel Lin mutex_lock(&data->update_lock); 707b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF4); 708b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (config < 0) { 709b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj dev_err(&client->dev, 710b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj "Error reading configuration register, aborting.\n"); 711cf44819c98db11163f58f08b822d626c7a8f5188Axel Lin count = config; 712cf44819c98db11163f58f08b822d626c7a8f5188Axel Lin goto EXIT; 713b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj } 714b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj switch (val) { 715b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj case 2: 716b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj config &= ~AMC6821_CONF4_PSPR; 717b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj data->fan1_div = 2; 718b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj break; 719b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj case 4: 720b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj config |= AMC6821_CONF4_PSPR; 721b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj data->fan1_div = 4; 722b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj break; 723b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj default: 724b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj count = -EINVAL; 725b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj goto EXIT; 726b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj } 727b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (i2c_smbus_write_byte_data(client, AMC6821_REG_CONF4, config)) { 728b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj dev_err(&client->dev, 729b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj "Configuration register write error, aborting.\n"); 730b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj count = -EIO; 731b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj } 732b5430a04e995081a308b4419bd0940f2badc6e6bTomaz MerteljEXIT: 733b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj mutex_unlock(&data->update_lock); 734b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return count; 735b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj} 736b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 737b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, 738b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj get_temp, NULL, IDX_TEMP1_INPUT); 739b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(temp1_min, S_IRUGO | S_IWUSR, get_temp, 740b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj set_temp, IDX_TEMP1_MIN); 741b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, get_temp, 742b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj set_temp, IDX_TEMP1_MAX); 743b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO | S_IWUSR, get_temp, 744b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj set_temp, IDX_TEMP1_CRIT); 745b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, 746b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj get_temp_alarm, NULL, IDX_TEMP1_MIN); 747b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, 748b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj get_temp_alarm, NULL, IDX_TEMP1_MAX); 749b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(temp1_crit_alarm, S_IRUGO, 750b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj get_temp_alarm, NULL, IDX_TEMP1_CRIT); 751df86754b746e9a0ff6f863f690b1c01d408e3cdcAxel Linstatic SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, 752b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj get_temp, NULL, IDX_TEMP2_INPUT); 753b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(temp2_min, S_IRUGO | S_IWUSR, get_temp, 754b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj set_temp, IDX_TEMP2_MIN); 755b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(temp2_max, S_IRUGO | S_IWUSR, get_temp, 756b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj set_temp, IDX_TEMP2_MAX); 757b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(temp2_crit, S_IRUGO | S_IWUSR, get_temp, 758b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj set_temp, IDX_TEMP2_CRIT); 759b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, 760b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj get_temp2_fault, NULL, 0); 761b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, 762b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj get_temp_alarm, NULL, IDX_TEMP2_MIN); 763b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, 764b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj get_temp_alarm, NULL, IDX_TEMP2_MAX); 765b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(temp2_crit_alarm, S_IRUGO, 766b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj get_temp_alarm, NULL, IDX_TEMP2_CRIT); 767b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, get_fan, NULL, IDX_FAN1_INPUT); 768b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(fan1_min, S_IRUGO | S_IWUSR, 769b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj get_fan, set_fan, IDX_FAN1_MIN); 770b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(fan1_max, S_IRUGO | S_IWUSR, 771b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj get_fan, set_fan, IDX_FAN1_MAX); 772b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(fan1_fault, S_IRUGO, get_fan1_fault, NULL, 0); 773b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR, 774b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj get_fan1_div, set_fan1_div, 0); 775b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 776b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, get_pwm1, set_pwm1, 0); 777b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, 778b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj get_pwm1_enable, set_pwm1_enable, 0); 779b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IRUGO, 780b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj get_pwm1_auto_point_pwm, NULL, 0); 781b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IWUSR | S_IRUGO, 782b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj get_pwm1_auto_point_pwm, set_pwm1_auto_point_pwm, 1); 783b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(pwm1_auto_point3_pwm, S_IRUGO, 784b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj get_pwm1_auto_point_pwm, NULL, 2); 785b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR(pwm1_auto_channels_temp, S_IRUGO, 786b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj get_pwm1_auto_channels_temp, NULL, 0); 787b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR_2(temp1_auto_point1_temp, S_IRUGO, 788b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj get_temp_auto_point_temp, NULL, 1, 0); 789b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR_2(temp1_auto_point2_temp, S_IWUSR | S_IRUGO, 790b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj get_temp_auto_point_temp, set_temp_auto_point_temp, 1, 1); 791b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR_2(temp1_auto_point3_temp, S_IWUSR | S_IRUGO, 792b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj get_temp_auto_point_temp, set_temp_auto_point_temp, 1, 2); 793b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 794b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR_2(temp2_auto_point1_temp, S_IWUSR | S_IRUGO, 795b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj get_temp_auto_point_temp, set_temp_auto_point_temp, 2, 0); 796b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR_2(temp2_auto_point2_temp, S_IWUSR | S_IRUGO, 797b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj get_temp_auto_point_temp, set_temp_auto_point_temp, 2, 1); 798b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic SENSOR_DEVICE_ATTR_2(temp2_auto_point3_temp, S_IWUSR | S_IRUGO, 799b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj get_temp_auto_point_temp, set_temp_auto_point_temp, 2, 2); 800b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 801b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic struct attribute *amc6821_attrs[] = { 802b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj &sensor_dev_attr_temp1_input.dev_attr.attr, 803b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj &sensor_dev_attr_temp1_min.dev_attr.attr, 804b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj &sensor_dev_attr_temp1_max.dev_attr.attr, 805b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj &sensor_dev_attr_temp1_crit.dev_attr.attr, 806b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, 807b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, 808b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr, 809b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj &sensor_dev_attr_temp2_input.dev_attr.attr, 810b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj &sensor_dev_attr_temp2_min.dev_attr.attr, 811b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj &sensor_dev_attr_temp2_max.dev_attr.attr, 812b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj &sensor_dev_attr_temp2_crit.dev_attr.attr, 813b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj &sensor_dev_attr_temp2_min_alarm.dev_attr.attr, 814b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, 815b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr, 816b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj &sensor_dev_attr_temp2_fault.dev_attr.attr, 817b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj &sensor_dev_attr_fan1_input.dev_attr.attr, 818b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj &sensor_dev_attr_fan1_min.dev_attr.attr, 819b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj &sensor_dev_attr_fan1_max.dev_attr.attr, 820b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj &sensor_dev_attr_fan1_fault.dev_attr.attr, 821b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj &sensor_dev_attr_fan1_div.dev_attr.attr, 822b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj &sensor_dev_attr_pwm1.dev_attr.attr, 823b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj &sensor_dev_attr_pwm1_enable.dev_attr.attr, 824b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj &sensor_dev_attr_pwm1_auto_channels_temp.dev_attr.attr, 825b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr, 826b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr, 827b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj &sensor_dev_attr_pwm1_auto_point3_pwm.dev_attr.attr, 828b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj &sensor_dev_attr_temp1_auto_point1_temp.dev_attr.attr, 829b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj &sensor_dev_attr_temp1_auto_point2_temp.dev_attr.attr, 830b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj &sensor_dev_attr_temp1_auto_point3_temp.dev_attr.attr, 831b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj &sensor_dev_attr_temp2_auto_point1_temp.dev_attr.attr, 832b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj &sensor_dev_attr_temp2_auto_point2_temp.dev_attr.attr, 833b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj &sensor_dev_attr_temp2_auto_point3_temp.dev_attr.attr, 834b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj NULL 835b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj}; 836b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 8371276fae2a93142525580d6f6ab77105f4d7a0e09Axel LinATTRIBUTE_GROUPS(amc6821); 838b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 839b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj/* Return 0 if detection is successful, -ENODEV otherwise */ 840b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic int amc6821_detect( 841b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct i2c_client *client, 842b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct i2c_board_info *info) 843b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{ 844b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj struct i2c_adapter *adapter = client->adapter; 845b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj int address = client->addr; 846b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj int dev_id, comp_id; 847b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 848b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj dev_dbg(&adapter->dev, "amc6821_detect called.\n"); 849b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 850b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { 851b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj dev_dbg(&adapter->dev, 852b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj "amc6821: I2C bus doesn't support byte mode, " 853b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj "skipping.\n"); 854b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return -ENODEV; 855b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj } 856b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 857b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj dev_id = i2c_smbus_read_byte_data(client, AMC6821_REG_DEV_ID); 858b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj comp_id = i2c_smbus_read_byte_data(client, AMC6821_REG_COMP_ID); 859b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (dev_id != 0x21 || comp_id != 0x49) { 860b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj dev_dbg(&adapter->dev, 861b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj "amc6821: detection failed at 0x%02x.\n", 862b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj address); 863b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return -ENODEV; 864b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj } 865b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 866ca3c7b63423c7f723258797bcb5b11652d32500bGuenter Roeck /* 867ca3c7b63423c7f723258797bcb5b11652d32500bGuenter Roeck * Bit 7 of the address register is ignored, so we can check the 868ca3c7b63423c7f723258797bcb5b11652d32500bGuenter Roeck * ID registers again 869ca3c7b63423c7f723258797bcb5b11652d32500bGuenter Roeck */ 870b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj dev_id = i2c_smbus_read_byte_data(client, 0x80 | AMC6821_REG_DEV_ID); 871b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj comp_id = i2c_smbus_read_byte_data(client, 0x80 | AMC6821_REG_COMP_ID); 872b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (dev_id != 0x21 || comp_id != 0x49) { 873b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj dev_dbg(&adapter->dev, 874b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj "amc6821: detection failed at 0x%02x.\n", 875b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj address); 876b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return -ENODEV; 877b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj } 878b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 879b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj dev_info(&adapter->dev, "amc6821: chip found at 0x%02x.\n", address); 880b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj strlcpy(info->type, "amc6821", I2C_NAME_SIZE); 881b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 882b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return 0; 883b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj} 884b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 885b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Merteljstatic int amc6821_init_client(struct i2c_client *client) 886b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{ 887b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj int config; 888b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj int err = -EIO; 889b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 890b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (init) { 891b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF4); 892b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 893b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (config < 0) { 894b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj dev_err(&client->dev, 895b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj "Error reading configuration register, aborting.\n"); 896b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return err; 897b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj } 898b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 899b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj config |= AMC6821_CONF4_MODE; 900b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 901b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (i2c_smbus_write_byte_data(client, AMC6821_REG_CONF4, 902b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj config)) { 903b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj dev_err(&client->dev, 904b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj "Configuration register write error, aborting.\n"); 905b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return err; 906b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj } 907b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 908b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF3); 909b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 910b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (config < 0) { 911b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj dev_err(&client->dev, 912b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj "Error reading configuration register, aborting.\n"); 913b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return err; 914b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj } 915b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 916b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj dev_info(&client->dev, "Revision %d\n", config & 0x0f); 917b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 918b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj config &= ~AMC6821_CONF3_THERM_FAN_EN; 919b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 920b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (i2c_smbus_write_byte_data(client, AMC6821_REG_CONF3, 921b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj config)) { 922b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj dev_err(&client->dev, 923b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj "Configuration register write error, aborting.\n"); 924b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return err; 925b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj } 926b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 927b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF2); 928b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 929b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (config < 0) { 930b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj dev_err(&client->dev, 931b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj "Error reading configuration register, aborting.\n"); 932b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return err; 933b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj } 934b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 935b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj config &= ~AMC6821_CONF2_RTFIE; 936b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj config &= ~AMC6821_CONF2_LTOIE; 937b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj config &= ~AMC6821_CONF2_RTOIE; 938b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (i2c_smbus_write_byte_data(client, 939b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj AMC6821_REG_CONF2, config)) { 940b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj dev_err(&client->dev, 941b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj "Configuration register write error, aborting.\n"); 942b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return err; 943b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj } 944b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 945b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj config = i2c_smbus_read_byte_data(client, AMC6821_REG_CONF1); 946b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 947b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (config < 0) { 948b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj dev_err(&client->dev, 949b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj "Error reading configuration register, aborting.\n"); 950b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return err; 951b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj } 952b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 953b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj config &= ~AMC6821_CONF1_THERMOVIE; 954b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj config &= ~AMC6821_CONF1_FANIE; 955b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj config |= AMC6821_CONF1_START; 956b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (pwminv) 957b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj config |= AMC6821_CONF1_PWMINV; 958b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj else 959b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj config &= ~AMC6821_CONF1_PWMINV; 960b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 961b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj if (i2c_smbus_write_byte_data( 962b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj client, AMC6821_REG_CONF1, config)) { 963b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj dev_err(&client->dev, 964b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj "Configuration register write error, aborting.\n"); 965b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return err; 966b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj } 967b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj } 968b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj return 0; 969b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj} 970b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 97128e6274d8fa67ecb468eaa219c45595384e3bda8Axel Linstatic int amc6821_probe(struct i2c_client *client, 97228e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin const struct i2c_device_id *id) 973b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj{ 9741276fae2a93142525580d6f6ab77105f4d7a0e09Axel Lin struct device *dev = &client->dev; 97528e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin struct amc6821_data *data; 9761276fae2a93142525580d6f6ab77105f4d7a0e09Axel Lin struct device *hwmon_dev; 97728e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin int err; 978b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 9791276fae2a93142525580d6f6ab77105f4d7a0e09Axel Lin data = devm_kzalloc(dev, sizeof(struct amc6821_data), GFP_KERNEL); 98028e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin if (!data) 98128e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin return -ENOMEM; 982b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 9831276fae2a93142525580d6f6ab77105f4d7a0e09Axel Lin data->client = client; 98428e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin mutex_init(&data->update_lock); 985b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 98628e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin /* 98728e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin * Initialize the amc6821 chip 98828e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin */ 98928e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin err = amc6821_init_client(client); 99028e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin if (err) 99128e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin return err; 992b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 9931276fae2a93142525580d6f6ab77105f4d7a0e09Axel Lin hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, 9941276fae2a93142525580d6f6ab77105f4d7a0e09Axel Lin data, 9951276fae2a93142525580d6f6ab77105f4d7a0e09Axel Lin amc6821_groups); 9961276fae2a93142525580d6f6ab77105f4d7a0e09Axel Lin return PTR_ERR_OR_ZERO(hwmon_dev); 997b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj} 998b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 99928e6274d8fa67ecb468eaa219c45595384e3bda8Axel Linstatic const struct i2c_device_id amc6821_id[] = { 100028e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin { "amc6821", amc6821 }, 100128e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin { } 100228e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin}; 100328e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin 100428e6274d8fa67ecb468eaa219c45595384e3bda8Axel LinMODULE_DEVICE_TABLE(i2c, amc6821_id); 100528e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin 100628e6274d8fa67ecb468eaa219c45595384e3bda8Axel Linstatic struct i2c_driver amc6821_driver = { 100728e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin .class = I2C_CLASS_HWMON, 100828e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin .driver = { 100928e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin .name = "amc6821", 101028e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin }, 101128e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin .probe = amc6821_probe, 101228e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin .id_table = amc6821_id, 101328e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin .detect = amc6821_detect, 101428e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin .address_list = normal_i2c, 101528e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin}; 101628e6274d8fa67ecb468eaa219c45595384e3bda8Axel Lin 1017f0967eea80ec2a19a4fe1ad27e3ff1b22c79a3c7Axel Linmodule_i2c_driver(amc6821_driver); 1018b5430a04e995081a308b4419bd0940f2badc6e6bTomaz Mertelj 1019b5430a04e995081a308b4419bd0940f2badc6e6bTomaz MerteljMODULE_LICENSE("GPL"); 1020b5430a04e995081a308b4419bd0940f2badc6e6bTomaz MerteljMODULE_AUTHOR("T. Mertelj <tomaz.mertelj@guest.arnes.si>"); 1021b5430a04e995081a308b4419bd0940f2badc6e6bTomaz MerteljMODULE_DESCRIPTION("Texas Instruments amc6821 hwmon driver"); 1022