18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * abituguru.c Copyright (c) 2005-2006 Hans de Goede <hdegoede@redhat.com> 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci/* 68c2ecf20Sopenharmony_ci * This driver supports the sensor part of the first and second revision of 78c2ecf20Sopenharmony_ci * the custom Abit uGuru chip found on Abit uGuru motherboards. Note: because 88c2ecf20Sopenharmony_ci * of lack of specs the CPU/RAM voltage & frequency control is not supported! 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/sched.h> 158c2ecf20Sopenharmony_ci#include <linux/init.h> 168c2ecf20Sopenharmony_ci#include <linux/slab.h> 178c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 188c2ecf20Sopenharmony_ci#include <linux/mutex.h> 198c2ecf20Sopenharmony_ci#include <linux/err.h> 208c2ecf20Sopenharmony_ci#include <linux/delay.h> 218c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 228c2ecf20Sopenharmony_ci#include <linux/hwmon.h> 238c2ecf20Sopenharmony_ci#include <linux/hwmon-sysfs.h> 248c2ecf20Sopenharmony_ci#include <linux/dmi.h> 258c2ecf20Sopenharmony_ci#include <linux/io.h> 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* Banks */ 288c2ecf20Sopenharmony_ci#define ABIT_UGURU_ALARM_BANK 0x20 /* 1x 3 bytes */ 298c2ecf20Sopenharmony_ci#define ABIT_UGURU_SENSOR_BANK1 0x21 /* 16x volt and temp */ 308c2ecf20Sopenharmony_ci#define ABIT_UGURU_FAN_PWM 0x24 /* 3x 5 bytes */ 318c2ecf20Sopenharmony_ci#define ABIT_UGURU_SENSOR_BANK2 0x26 /* fans */ 328c2ecf20Sopenharmony_ci/* max nr of sensors in bank1, a bank1 sensor can be in, temp or nc */ 338c2ecf20Sopenharmony_ci#define ABIT_UGURU_MAX_BANK1_SENSORS 16 348c2ecf20Sopenharmony_ci/* 358c2ecf20Sopenharmony_ci * Warning if you increase one of the 2 MAX defines below to 10 or higher you 368c2ecf20Sopenharmony_ci * should adjust the belonging _NAMES_LENGTH macro for the 2 digit number! 378c2ecf20Sopenharmony_ci */ 388c2ecf20Sopenharmony_ci/* max nr of sensors in bank2, currently mb's with max 6 fans are known */ 398c2ecf20Sopenharmony_ci#define ABIT_UGURU_MAX_BANK2_SENSORS 6 408c2ecf20Sopenharmony_ci/* max nr of pwm outputs, currently mb's with max 5 pwm outputs are known */ 418c2ecf20Sopenharmony_ci#define ABIT_UGURU_MAX_PWMS 5 428c2ecf20Sopenharmony_ci/* uGuru sensor bank 1 flags */ /* Alarm if: */ 438c2ecf20Sopenharmony_ci#define ABIT_UGURU_TEMP_HIGH_ALARM_ENABLE 0x01 /* temp over warn */ 448c2ecf20Sopenharmony_ci#define ABIT_UGURU_VOLT_HIGH_ALARM_ENABLE 0x02 /* volt over max */ 458c2ecf20Sopenharmony_ci#define ABIT_UGURU_VOLT_LOW_ALARM_ENABLE 0x04 /* volt under min */ 468c2ecf20Sopenharmony_ci#define ABIT_UGURU_TEMP_HIGH_ALARM_FLAG 0x10 /* temp is over warn */ 478c2ecf20Sopenharmony_ci#define ABIT_UGURU_VOLT_HIGH_ALARM_FLAG 0x20 /* volt is over max */ 488c2ecf20Sopenharmony_ci#define ABIT_UGURU_VOLT_LOW_ALARM_FLAG 0x40 /* volt is under min */ 498c2ecf20Sopenharmony_ci/* uGuru sensor bank 2 flags */ /* Alarm if: */ 508c2ecf20Sopenharmony_ci#define ABIT_UGURU_FAN_LOW_ALARM_ENABLE 0x01 /* fan under min */ 518c2ecf20Sopenharmony_ci/* uGuru sensor bank common flags */ 528c2ecf20Sopenharmony_ci#define ABIT_UGURU_BEEP_ENABLE 0x08 /* beep if alarm */ 538c2ecf20Sopenharmony_ci#define ABIT_UGURU_SHUTDOWN_ENABLE 0x80 /* shutdown if alarm */ 548c2ecf20Sopenharmony_ci/* uGuru fan PWM (speed control) flags */ 558c2ecf20Sopenharmony_ci#define ABIT_UGURU_FAN_PWM_ENABLE 0x80 /* enable speed control */ 568c2ecf20Sopenharmony_ci/* Values used for conversion */ 578c2ecf20Sopenharmony_ci#define ABIT_UGURU_FAN_MAX 15300 /* RPM */ 588c2ecf20Sopenharmony_ci/* Bank1 sensor types */ 598c2ecf20Sopenharmony_ci#define ABIT_UGURU_IN_SENSOR 0 608c2ecf20Sopenharmony_ci#define ABIT_UGURU_TEMP_SENSOR 1 618c2ecf20Sopenharmony_ci#define ABIT_UGURU_NC 2 628c2ecf20Sopenharmony_ci/* 638c2ecf20Sopenharmony_ci * In many cases we need to wait for the uGuru to reach a certain status, most 648c2ecf20Sopenharmony_ci * of the time it will reach this status within 30 - 90 ISA reads, and thus we 658c2ecf20Sopenharmony_ci * can best busy wait. This define gives the total amount of reads to try. 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_ci#define ABIT_UGURU_WAIT_TIMEOUT 125 688c2ecf20Sopenharmony_ci/* 698c2ecf20Sopenharmony_ci * However sometimes older versions of the uGuru seem to be distracted and they 708c2ecf20Sopenharmony_ci * do not respond for a long time. To handle this we sleep before each of the 718c2ecf20Sopenharmony_ci * last ABIT_UGURU_WAIT_TIMEOUT_SLEEP tries. 728c2ecf20Sopenharmony_ci */ 738c2ecf20Sopenharmony_ci#define ABIT_UGURU_WAIT_TIMEOUT_SLEEP 5 748c2ecf20Sopenharmony_ci/* 758c2ecf20Sopenharmony_ci * Normally all expected status in abituguru_ready, are reported after the 768c2ecf20Sopenharmony_ci * first read, but sometimes not and we need to poll. 778c2ecf20Sopenharmony_ci */ 788c2ecf20Sopenharmony_ci#define ABIT_UGURU_READY_TIMEOUT 5 798c2ecf20Sopenharmony_ci/* Maximum 3 retries on timedout reads/writes, delay 200 ms before retrying */ 808c2ecf20Sopenharmony_ci#define ABIT_UGURU_MAX_RETRIES 3 818c2ecf20Sopenharmony_ci#define ABIT_UGURU_RETRY_DELAY (HZ/5) 828c2ecf20Sopenharmony_ci/* Maximum 2 timeouts in abituguru_update_device, iow 3 in a row is an error */ 838c2ecf20Sopenharmony_ci#define ABIT_UGURU_MAX_TIMEOUTS 2 848c2ecf20Sopenharmony_ci/* utility macros */ 858c2ecf20Sopenharmony_ci#define ABIT_UGURU_NAME "abituguru" 868c2ecf20Sopenharmony_ci#define ABIT_UGURU_DEBUG(level, format, arg...) \ 878c2ecf20Sopenharmony_ci do { \ 888c2ecf20Sopenharmony_ci if (level <= verbose) \ 898c2ecf20Sopenharmony_ci pr_debug(format , ## arg); \ 908c2ecf20Sopenharmony_ci } while (0) 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci/* Macros to help calculate the sysfs_names array length */ 938c2ecf20Sopenharmony_ci/* 948c2ecf20Sopenharmony_ci * sum of strlen of: in??_input\0, in??_{min,max}\0, in??_{min,max}_alarm\0, 958c2ecf20Sopenharmony_ci * in??_{min,max}_alarm_enable\0, in??_beep\0, in??_shutdown\0 968c2ecf20Sopenharmony_ci */ 978c2ecf20Sopenharmony_ci#define ABITUGURU_IN_NAMES_LENGTH (11 + 2 * 9 + 2 * 15 + 2 * 22 + 10 + 14) 988c2ecf20Sopenharmony_ci/* 998c2ecf20Sopenharmony_ci * sum of strlen of: temp??_input\0, temp??_max\0, temp??_crit\0, 1008c2ecf20Sopenharmony_ci * temp??_alarm\0, temp??_alarm_enable\0, temp??_beep\0, temp??_shutdown\0 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_ci#define ABITUGURU_TEMP_NAMES_LENGTH (13 + 11 + 12 + 13 + 20 + 12 + 16) 1038c2ecf20Sopenharmony_ci/* 1048c2ecf20Sopenharmony_ci * sum of strlen of: fan?_input\0, fan?_min\0, fan?_alarm\0, 1058c2ecf20Sopenharmony_ci * fan?_alarm_enable\0, fan?_beep\0, fan?_shutdown\0 1068c2ecf20Sopenharmony_ci */ 1078c2ecf20Sopenharmony_ci#define ABITUGURU_FAN_NAMES_LENGTH (11 + 9 + 11 + 18 + 10 + 14) 1088c2ecf20Sopenharmony_ci/* 1098c2ecf20Sopenharmony_ci * sum of strlen of: pwm?_enable\0, pwm?_auto_channels_temp\0, 1108c2ecf20Sopenharmony_ci * pwm?_auto_point{1,2}_pwm\0, pwm?_auto_point{1,2}_temp\0 1118c2ecf20Sopenharmony_ci */ 1128c2ecf20Sopenharmony_ci#define ABITUGURU_PWM_NAMES_LENGTH (12 + 24 + 2 * 21 + 2 * 22) 1138c2ecf20Sopenharmony_ci/* IN_NAMES_LENGTH > TEMP_NAMES_LENGTH so assume all bank1 sensors are in */ 1148c2ecf20Sopenharmony_ci#define ABITUGURU_SYSFS_NAMES_LENGTH ( \ 1158c2ecf20Sopenharmony_ci ABIT_UGURU_MAX_BANK1_SENSORS * ABITUGURU_IN_NAMES_LENGTH + \ 1168c2ecf20Sopenharmony_ci ABIT_UGURU_MAX_BANK2_SENSORS * ABITUGURU_FAN_NAMES_LENGTH + \ 1178c2ecf20Sopenharmony_ci ABIT_UGURU_MAX_PWMS * ABITUGURU_PWM_NAMES_LENGTH) 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci/* 1208c2ecf20Sopenharmony_ci * All the macros below are named identical to the oguru and oguru2 programs 1218c2ecf20Sopenharmony_ci * reverse engineered by Olle Sandberg, hence the names might not be 100% 1228c2ecf20Sopenharmony_ci * logical. I could come up with better names, but I prefer keeping the names 1238c2ecf20Sopenharmony_ci * identical so that this driver can be compared with his work more easily. 1248c2ecf20Sopenharmony_ci */ 1258c2ecf20Sopenharmony_ci/* Two i/o-ports are used by uGuru */ 1268c2ecf20Sopenharmony_ci#define ABIT_UGURU_BASE 0x00E0 1278c2ecf20Sopenharmony_ci/* Used to tell uGuru what to read and to read the actual data */ 1288c2ecf20Sopenharmony_ci#define ABIT_UGURU_CMD 0x00 1298c2ecf20Sopenharmony_ci/* Mostly used to check if uGuru is busy */ 1308c2ecf20Sopenharmony_ci#define ABIT_UGURU_DATA 0x04 1318c2ecf20Sopenharmony_ci#define ABIT_UGURU_REGION_LENGTH 5 1328c2ecf20Sopenharmony_ci/* uGuru status' */ 1338c2ecf20Sopenharmony_ci#define ABIT_UGURU_STATUS_WRITE 0x00 /* Ready to be written */ 1348c2ecf20Sopenharmony_ci#define ABIT_UGURU_STATUS_READ 0x01 /* Ready to be read */ 1358c2ecf20Sopenharmony_ci#define ABIT_UGURU_STATUS_INPUT 0x08 /* More input */ 1368c2ecf20Sopenharmony_ci#define ABIT_UGURU_STATUS_READY 0x09 /* Ready to be written */ 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci/* Constants */ 1398c2ecf20Sopenharmony_ci/* in (Volt) sensors go up to 3494 mV, temp to 255000 millidegrees Celsius */ 1408c2ecf20Sopenharmony_cistatic const int abituguru_bank1_max_value[2] = { 3494, 255000 }; 1418c2ecf20Sopenharmony_ci/* 1428c2ecf20Sopenharmony_ci * Min / Max allowed values for sensor2 (fan) alarm threshold, these values 1438c2ecf20Sopenharmony_ci * correspond to 300-3000 RPM 1448c2ecf20Sopenharmony_ci */ 1458c2ecf20Sopenharmony_cistatic const u8 abituguru_bank2_min_threshold = 5; 1468c2ecf20Sopenharmony_cistatic const u8 abituguru_bank2_max_threshold = 50; 1478c2ecf20Sopenharmony_ci/* 1488c2ecf20Sopenharmony_ci * Register 0 is a bitfield, 1 and 2 are pwm settings (255 = 100%), 3 and 4 1498c2ecf20Sopenharmony_ci * are temperature trip points. 1508c2ecf20Sopenharmony_ci */ 1518c2ecf20Sopenharmony_cistatic const int abituguru_pwm_settings_multiplier[5] = { 0, 1, 1, 1000, 1000 }; 1528c2ecf20Sopenharmony_ci/* 1538c2ecf20Sopenharmony_ci * Min / Max allowed values for pwm_settings. Note: pwm1 (CPU fan) is a 1548c2ecf20Sopenharmony_ci * special case the minimum allowed pwm% setting for this is 30% (77) on 1558c2ecf20Sopenharmony_ci * some MB's this special case is handled in the code! 1568c2ecf20Sopenharmony_ci */ 1578c2ecf20Sopenharmony_cistatic const u8 abituguru_pwm_min[5] = { 0, 170, 170, 25, 25 }; 1588c2ecf20Sopenharmony_cistatic const u8 abituguru_pwm_max[5] = { 0, 255, 255, 75, 75 }; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci/* Insmod parameters */ 1628c2ecf20Sopenharmony_cistatic bool force; 1638c2ecf20Sopenharmony_cimodule_param(force, bool, 0); 1648c2ecf20Sopenharmony_ciMODULE_PARM_DESC(force, "Set to one to force detection."); 1658c2ecf20Sopenharmony_cistatic int bank1_types[ABIT_UGURU_MAX_BANK1_SENSORS] = { -1, -1, -1, -1, -1, 1668c2ecf20Sopenharmony_ci -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; 1678c2ecf20Sopenharmony_cimodule_param_array(bank1_types, int, NULL, 0); 1688c2ecf20Sopenharmony_ciMODULE_PARM_DESC(bank1_types, "Bank1 sensortype autodetection override:\n" 1698c2ecf20Sopenharmony_ci " -1 autodetect\n" 1708c2ecf20Sopenharmony_ci " 0 volt sensor\n" 1718c2ecf20Sopenharmony_ci " 1 temp sensor\n" 1728c2ecf20Sopenharmony_ci " 2 not connected"); 1738c2ecf20Sopenharmony_cistatic int fan_sensors; 1748c2ecf20Sopenharmony_cimodule_param(fan_sensors, int, 0); 1758c2ecf20Sopenharmony_ciMODULE_PARM_DESC(fan_sensors, "Number of fan sensors on the uGuru " 1768c2ecf20Sopenharmony_ci "(0 = autodetect)"); 1778c2ecf20Sopenharmony_cistatic int pwms; 1788c2ecf20Sopenharmony_cimodule_param(pwms, int, 0); 1798c2ecf20Sopenharmony_ciMODULE_PARM_DESC(pwms, "Number of PWMs on the uGuru " 1808c2ecf20Sopenharmony_ci "(0 = autodetect)"); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci/* Default verbose is 2, since this driver is still in the testing phase */ 1838c2ecf20Sopenharmony_cistatic int verbose = 2; 1848c2ecf20Sopenharmony_cimodule_param(verbose, int, 0644); 1858c2ecf20Sopenharmony_ciMODULE_PARM_DESC(verbose, "How verbose should the driver be? (0-3):\n" 1868c2ecf20Sopenharmony_ci " 0 normal output\n" 1878c2ecf20Sopenharmony_ci " 1 + verbose error reporting\n" 1888c2ecf20Sopenharmony_ci " 2 + sensors type probing info\n" 1898c2ecf20Sopenharmony_ci " 3 + retryable error reporting"); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci/* 1938c2ecf20Sopenharmony_ci * For the Abit uGuru, we need to keep some data in memory. 1948c2ecf20Sopenharmony_ci * The structure is dynamically allocated, at the same time when a new 1958c2ecf20Sopenharmony_ci * abituguru device is allocated. 1968c2ecf20Sopenharmony_ci */ 1978c2ecf20Sopenharmony_cistruct abituguru_data { 1988c2ecf20Sopenharmony_ci struct device *hwmon_dev; /* hwmon registered device */ 1998c2ecf20Sopenharmony_ci struct mutex update_lock; /* protect access to data and uGuru */ 2008c2ecf20Sopenharmony_ci unsigned long last_updated; /* In jiffies */ 2018c2ecf20Sopenharmony_ci unsigned short addr; /* uguru base address */ 2028c2ecf20Sopenharmony_ci char uguru_ready; /* is the uguru in ready state? */ 2038c2ecf20Sopenharmony_ci unsigned char update_timeouts; /* 2048c2ecf20Sopenharmony_ci * number of update timeouts since last 2058c2ecf20Sopenharmony_ci * successful update 2068c2ecf20Sopenharmony_ci */ 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci /* 2098c2ecf20Sopenharmony_ci * The sysfs attr and their names are generated automatically, for bank1 2108c2ecf20Sopenharmony_ci * we cannot use a predefined array because we don't know beforehand 2118c2ecf20Sopenharmony_ci * of a sensor is a volt or a temp sensor, for bank2 and the pwms its 2128c2ecf20Sopenharmony_ci * easier todo things the same way. For in sensors we have 9 (temp 7) 2138c2ecf20Sopenharmony_ci * sysfs entries per sensor, for bank2 and pwms 6. 2148c2ecf20Sopenharmony_ci */ 2158c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 sysfs_attr[ 2168c2ecf20Sopenharmony_ci ABIT_UGURU_MAX_BANK1_SENSORS * 9 + 2178c2ecf20Sopenharmony_ci ABIT_UGURU_MAX_BANK2_SENSORS * 6 + ABIT_UGURU_MAX_PWMS * 6]; 2188c2ecf20Sopenharmony_ci /* Buffer to store the dynamically generated sysfs names */ 2198c2ecf20Sopenharmony_ci char sysfs_names[ABITUGURU_SYSFS_NAMES_LENGTH]; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci /* Bank 1 data */ 2228c2ecf20Sopenharmony_ci /* number of and addresses of [0] in, [1] temp sensors */ 2238c2ecf20Sopenharmony_ci u8 bank1_sensors[2]; 2248c2ecf20Sopenharmony_ci u8 bank1_address[2][ABIT_UGURU_MAX_BANK1_SENSORS]; 2258c2ecf20Sopenharmony_ci u8 bank1_value[ABIT_UGURU_MAX_BANK1_SENSORS]; 2268c2ecf20Sopenharmony_ci /* 2278c2ecf20Sopenharmony_ci * This array holds 3 entries per sensor for the bank 1 sensor settings 2288c2ecf20Sopenharmony_ci * (flags, min, max for voltage / flags, warn, shutdown for temp). 2298c2ecf20Sopenharmony_ci */ 2308c2ecf20Sopenharmony_ci u8 bank1_settings[ABIT_UGURU_MAX_BANK1_SENSORS][3]; 2318c2ecf20Sopenharmony_ci /* 2328c2ecf20Sopenharmony_ci * Maximum value for each sensor used for scaling in mV/millidegrees 2338c2ecf20Sopenharmony_ci * Celsius. 2348c2ecf20Sopenharmony_ci */ 2358c2ecf20Sopenharmony_ci int bank1_max_value[ABIT_UGURU_MAX_BANK1_SENSORS]; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci /* Bank 2 data, ABIT_UGURU_MAX_BANK2_SENSORS entries for bank2 */ 2388c2ecf20Sopenharmony_ci u8 bank2_sensors; /* actual number of bank2 sensors found */ 2398c2ecf20Sopenharmony_ci u8 bank2_value[ABIT_UGURU_MAX_BANK2_SENSORS]; 2408c2ecf20Sopenharmony_ci u8 bank2_settings[ABIT_UGURU_MAX_BANK2_SENSORS][2]; /* flags, min */ 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci /* Alarms 2 bytes for bank1, 1 byte for bank2 */ 2438c2ecf20Sopenharmony_ci u8 alarms[3]; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci /* Fan PWM (speed control) 5 bytes per PWM */ 2468c2ecf20Sopenharmony_ci u8 pwms; /* actual number of pwms found */ 2478c2ecf20Sopenharmony_ci u8 pwm_settings[ABIT_UGURU_MAX_PWMS][5]; 2488c2ecf20Sopenharmony_ci}; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic const char *never_happen = "This should never happen."; 2518c2ecf20Sopenharmony_cistatic const char *report_this = 2528c2ecf20Sopenharmony_ci "Please report this to the abituguru maintainer (see MAINTAINERS)"; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci/* wait till the uguru is in the specified state */ 2558c2ecf20Sopenharmony_cistatic int abituguru_wait(struct abituguru_data *data, u8 state) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci int timeout = ABIT_UGURU_WAIT_TIMEOUT; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci while (inb_p(data->addr + ABIT_UGURU_DATA) != state) { 2608c2ecf20Sopenharmony_ci timeout--; 2618c2ecf20Sopenharmony_ci if (timeout == 0) 2628c2ecf20Sopenharmony_ci return -EBUSY; 2638c2ecf20Sopenharmony_ci /* 2648c2ecf20Sopenharmony_ci * sleep a bit before our last few tries, see the comment on 2658c2ecf20Sopenharmony_ci * this where ABIT_UGURU_WAIT_TIMEOUT_SLEEP is defined. 2668c2ecf20Sopenharmony_ci */ 2678c2ecf20Sopenharmony_ci if (timeout <= ABIT_UGURU_WAIT_TIMEOUT_SLEEP) 2688c2ecf20Sopenharmony_ci msleep(0); 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci return 0; 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci/* Put the uguru in ready for input state */ 2748c2ecf20Sopenharmony_cistatic int abituguru_ready(struct abituguru_data *data) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci int timeout = ABIT_UGURU_READY_TIMEOUT; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (data->uguru_ready) 2798c2ecf20Sopenharmony_ci return 0; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci /* Reset? / Prepare for next read/write cycle */ 2828c2ecf20Sopenharmony_ci outb(0x00, data->addr + ABIT_UGURU_DATA); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci /* Wait till the uguru is ready */ 2858c2ecf20Sopenharmony_ci if (abituguru_wait(data, ABIT_UGURU_STATUS_READY)) { 2868c2ecf20Sopenharmony_ci ABIT_UGURU_DEBUG(1, 2878c2ecf20Sopenharmony_ci "timeout exceeded waiting for ready state\n"); 2888c2ecf20Sopenharmony_ci return -EIO; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci /* Cmd port MUST be read now and should contain 0xAC */ 2928c2ecf20Sopenharmony_ci while (inb_p(data->addr + ABIT_UGURU_CMD) != 0xAC) { 2938c2ecf20Sopenharmony_ci timeout--; 2948c2ecf20Sopenharmony_ci if (timeout == 0) { 2958c2ecf20Sopenharmony_ci ABIT_UGURU_DEBUG(1, 2968c2ecf20Sopenharmony_ci "CMD reg does not hold 0xAC after ready command\n"); 2978c2ecf20Sopenharmony_ci return -EIO; 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci msleep(0); 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci /* 3038c2ecf20Sopenharmony_ci * After this the ABIT_UGURU_DATA port should contain 3048c2ecf20Sopenharmony_ci * ABIT_UGURU_STATUS_INPUT 3058c2ecf20Sopenharmony_ci */ 3068c2ecf20Sopenharmony_ci timeout = ABIT_UGURU_READY_TIMEOUT; 3078c2ecf20Sopenharmony_ci while (inb_p(data->addr + ABIT_UGURU_DATA) != ABIT_UGURU_STATUS_INPUT) { 3088c2ecf20Sopenharmony_ci timeout--; 3098c2ecf20Sopenharmony_ci if (timeout == 0) { 3108c2ecf20Sopenharmony_ci ABIT_UGURU_DEBUG(1, 3118c2ecf20Sopenharmony_ci "state != more input after ready command\n"); 3128c2ecf20Sopenharmony_ci return -EIO; 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci msleep(0); 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci data->uguru_ready = 1; 3188c2ecf20Sopenharmony_ci return 0; 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci/* 3228c2ecf20Sopenharmony_ci * Send the bank and then sensor address to the uGuru for the next read/write 3238c2ecf20Sopenharmony_ci * cycle. This function gets called as the first part of a read/write by 3248c2ecf20Sopenharmony_ci * abituguru_read and abituguru_write. This function should never be 3258c2ecf20Sopenharmony_ci * called by any other function. 3268c2ecf20Sopenharmony_ci */ 3278c2ecf20Sopenharmony_cistatic int abituguru_send_address(struct abituguru_data *data, 3288c2ecf20Sopenharmony_ci u8 bank_addr, u8 sensor_addr, int retries) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci /* 3318c2ecf20Sopenharmony_ci * assume the caller does error handling itself if it has not requested 3328c2ecf20Sopenharmony_ci * any retries, and thus be quiet. 3338c2ecf20Sopenharmony_ci */ 3348c2ecf20Sopenharmony_ci int report_errors = retries; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci for (;;) { 3378c2ecf20Sopenharmony_ci /* 3388c2ecf20Sopenharmony_ci * Make sure the uguru is ready and then send the bank address, 3398c2ecf20Sopenharmony_ci * after this the uguru is no longer "ready". 3408c2ecf20Sopenharmony_ci */ 3418c2ecf20Sopenharmony_ci if (abituguru_ready(data) != 0) 3428c2ecf20Sopenharmony_ci return -EIO; 3438c2ecf20Sopenharmony_ci outb(bank_addr, data->addr + ABIT_UGURU_DATA); 3448c2ecf20Sopenharmony_ci data->uguru_ready = 0; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci /* 3478c2ecf20Sopenharmony_ci * Wait till the uguru is ABIT_UGURU_STATUS_INPUT state again 3488c2ecf20Sopenharmony_ci * and send the sensor addr 3498c2ecf20Sopenharmony_ci */ 3508c2ecf20Sopenharmony_ci if (abituguru_wait(data, ABIT_UGURU_STATUS_INPUT)) { 3518c2ecf20Sopenharmony_ci if (retries) { 3528c2ecf20Sopenharmony_ci ABIT_UGURU_DEBUG(3, "timeout exceeded " 3538c2ecf20Sopenharmony_ci "waiting for more input state, %d " 3548c2ecf20Sopenharmony_ci "tries remaining\n", retries); 3558c2ecf20Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 3568c2ecf20Sopenharmony_ci schedule_timeout(ABIT_UGURU_RETRY_DELAY); 3578c2ecf20Sopenharmony_ci retries--; 3588c2ecf20Sopenharmony_ci continue; 3598c2ecf20Sopenharmony_ci } 3608c2ecf20Sopenharmony_ci if (report_errors) 3618c2ecf20Sopenharmony_ci ABIT_UGURU_DEBUG(1, "timeout exceeded " 3628c2ecf20Sopenharmony_ci "waiting for more input state " 3638c2ecf20Sopenharmony_ci "(bank: %d)\n", (int)bank_addr); 3648c2ecf20Sopenharmony_ci return -EBUSY; 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci outb(sensor_addr, data->addr + ABIT_UGURU_CMD); 3678c2ecf20Sopenharmony_ci return 0; 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci} 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci/* 3728c2ecf20Sopenharmony_ci * Read count bytes from sensor sensor_addr in bank bank_addr and store the 3738c2ecf20Sopenharmony_ci * result in buf, retry the send address part of the read retries times. 3748c2ecf20Sopenharmony_ci */ 3758c2ecf20Sopenharmony_cistatic int abituguru_read(struct abituguru_data *data, 3768c2ecf20Sopenharmony_ci u8 bank_addr, u8 sensor_addr, u8 *buf, int count, int retries) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci int i; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci /* Send the address */ 3818c2ecf20Sopenharmony_ci i = abituguru_send_address(data, bank_addr, sensor_addr, retries); 3828c2ecf20Sopenharmony_ci if (i) 3838c2ecf20Sopenharmony_ci return i; 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci /* And read the data */ 3868c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 3878c2ecf20Sopenharmony_ci if (abituguru_wait(data, ABIT_UGURU_STATUS_READ)) { 3888c2ecf20Sopenharmony_ci ABIT_UGURU_DEBUG(retries ? 1 : 3, 3898c2ecf20Sopenharmony_ci "timeout exceeded waiting for " 3908c2ecf20Sopenharmony_ci "read state (bank: %d, sensor: %d)\n", 3918c2ecf20Sopenharmony_ci (int)bank_addr, (int)sensor_addr); 3928c2ecf20Sopenharmony_ci break; 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci buf[i] = inb(data->addr + ABIT_UGURU_CMD); 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci /* Last put the chip back in ready state */ 3988c2ecf20Sopenharmony_ci abituguru_ready(data); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci return i; 4018c2ecf20Sopenharmony_ci} 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci/* 4048c2ecf20Sopenharmony_ci * Write count bytes from buf to sensor sensor_addr in bank bank_addr, the send 4058c2ecf20Sopenharmony_ci * address part of the write is always retried ABIT_UGURU_MAX_RETRIES times. 4068c2ecf20Sopenharmony_ci */ 4078c2ecf20Sopenharmony_cistatic int abituguru_write(struct abituguru_data *data, 4088c2ecf20Sopenharmony_ci u8 bank_addr, u8 sensor_addr, u8 *buf, int count) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci /* 4118c2ecf20Sopenharmony_ci * We use the ready timeout as we have to wait for 0xAC just like the 4128c2ecf20Sopenharmony_ci * ready function 4138c2ecf20Sopenharmony_ci */ 4148c2ecf20Sopenharmony_ci int i, timeout = ABIT_UGURU_READY_TIMEOUT; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci /* Send the address */ 4178c2ecf20Sopenharmony_ci i = abituguru_send_address(data, bank_addr, sensor_addr, 4188c2ecf20Sopenharmony_ci ABIT_UGURU_MAX_RETRIES); 4198c2ecf20Sopenharmony_ci if (i) 4208c2ecf20Sopenharmony_ci return i; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci /* And write the data */ 4238c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 4248c2ecf20Sopenharmony_ci if (abituguru_wait(data, ABIT_UGURU_STATUS_WRITE)) { 4258c2ecf20Sopenharmony_ci ABIT_UGURU_DEBUG(1, "timeout exceeded waiting for " 4268c2ecf20Sopenharmony_ci "write state (bank: %d, sensor: %d)\n", 4278c2ecf20Sopenharmony_ci (int)bank_addr, (int)sensor_addr); 4288c2ecf20Sopenharmony_ci break; 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci outb(buf[i], data->addr + ABIT_UGURU_CMD); 4318c2ecf20Sopenharmony_ci } 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci /* 4348c2ecf20Sopenharmony_ci * Now we need to wait till the chip is ready to be read again, 4358c2ecf20Sopenharmony_ci * so that we can read 0xAC as confirmation that our write has 4368c2ecf20Sopenharmony_ci * succeeded. 4378c2ecf20Sopenharmony_ci */ 4388c2ecf20Sopenharmony_ci if (abituguru_wait(data, ABIT_UGURU_STATUS_READ)) { 4398c2ecf20Sopenharmony_ci ABIT_UGURU_DEBUG(1, "timeout exceeded waiting for read state " 4408c2ecf20Sopenharmony_ci "after write (bank: %d, sensor: %d)\n", (int)bank_addr, 4418c2ecf20Sopenharmony_ci (int)sensor_addr); 4428c2ecf20Sopenharmony_ci return -EIO; 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci /* Cmd port MUST be read now and should contain 0xAC */ 4468c2ecf20Sopenharmony_ci while (inb_p(data->addr + ABIT_UGURU_CMD) != 0xAC) { 4478c2ecf20Sopenharmony_ci timeout--; 4488c2ecf20Sopenharmony_ci if (timeout == 0) { 4498c2ecf20Sopenharmony_ci ABIT_UGURU_DEBUG(1, "CMD reg does not hold 0xAC after " 4508c2ecf20Sopenharmony_ci "write (bank: %d, sensor: %d)\n", 4518c2ecf20Sopenharmony_ci (int)bank_addr, (int)sensor_addr); 4528c2ecf20Sopenharmony_ci return -EIO; 4538c2ecf20Sopenharmony_ci } 4548c2ecf20Sopenharmony_ci msleep(0); 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci /* Last put the chip back in ready state */ 4588c2ecf20Sopenharmony_ci abituguru_ready(data); 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci return i; 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci/* 4648c2ecf20Sopenharmony_ci * Detect sensor type. Temp and Volt sensors are enabled with 4658c2ecf20Sopenharmony_ci * different masks and will ignore enable masks not meant for them. 4668c2ecf20Sopenharmony_ci * This enables us to test what kind of sensor we're dealing with. 4678c2ecf20Sopenharmony_ci * By setting the alarm thresholds so that we will always get an 4688c2ecf20Sopenharmony_ci * alarm for sensor type X and then enabling the sensor as sensor type 4698c2ecf20Sopenharmony_ci * X, if we then get an alarm it is a sensor of type X. 4708c2ecf20Sopenharmony_ci */ 4718c2ecf20Sopenharmony_cistatic int 4728c2ecf20Sopenharmony_ciabituguru_detect_bank1_sensor_type(struct abituguru_data *data, 4738c2ecf20Sopenharmony_ci u8 sensor_addr) 4748c2ecf20Sopenharmony_ci{ 4758c2ecf20Sopenharmony_ci u8 val, test_flag, buf[3]; 4768c2ecf20Sopenharmony_ci int i, ret = -ENODEV; /* error is the most common used retval :| */ 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci /* If overriden by the user return the user selected type */ 4798c2ecf20Sopenharmony_ci if (bank1_types[sensor_addr] >= ABIT_UGURU_IN_SENSOR && 4808c2ecf20Sopenharmony_ci bank1_types[sensor_addr] <= ABIT_UGURU_NC) { 4818c2ecf20Sopenharmony_ci ABIT_UGURU_DEBUG(2, "assuming sensor type %d for bank1 sensor " 4828c2ecf20Sopenharmony_ci "%d because of \"bank1_types\" module param\n", 4838c2ecf20Sopenharmony_ci bank1_types[sensor_addr], (int)sensor_addr); 4848c2ecf20Sopenharmony_ci return bank1_types[sensor_addr]; 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci /* First read the sensor and the current settings */ 4888c2ecf20Sopenharmony_ci if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1, sensor_addr, &val, 4898c2ecf20Sopenharmony_ci 1, ABIT_UGURU_MAX_RETRIES) != 1) 4908c2ecf20Sopenharmony_ci return -ENODEV; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci /* Test val is sane / usable for sensor type detection. */ 4938c2ecf20Sopenharmony_ci if ((val < 10u) || (val > 250u)) { 4948c2ecf20Sopenharmony_ci pr_warn("bank1-sensor: %d reading (%d) too close to limits, " 4958c2ecf20Sopenharmony_ci "unable to determine sensor type, skipping sensor\n", 4968c2ecf20Sopenharmony_ci (int)sensor_addr, (int)val); 4978c2ecf20Sopenharmony_ci /* 4988c2ecf20Sopenharmony_ci * assume no sensor is there for sensors for which we can't 4998c2ecf20Sopenharmony_ci * determine the sensor type because their reading is too close 5008c2ecf20Sopenharmony_ci * to their limits, this usually means no sensor is there. 5018c2ecf20Sopenharmony_ci */ 5028c2ecf20Sopenharmony_ci return ABIT_UGURU_NC; 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci ABIT_UGURU_DEBUG(2, "testing bank1 sensor %d\n", (int)sensor_addr); 5068c2ecf20Sopenharmony_ci /* 5078c2ecf20Sopenharmony_ci * Volt sensor test, enable volt low alarm, set min value ridiculously 5088c2ecf20Sopenharmony_ci * high, or vica versa if the reading is very high. If its a volt 5098c2ecf20Sopenharmony_ci * sensor this should always give us an alarm. 5108c2ecf20Sopenharmony_ci */ 5118c2ecf20Sopenharmony_ci if (val <= 240u) { 5128c2ecf20Sopenharmony_ci buf[0] = ABIT_UGURU_VOLT_LOW_ALARM_ENABLE; 5138c2ecf20Sopenharmony_ci buf[1] = 245; 5148c2ecf20Sopenharmony_ci buf[2] = 250; 5158c2ecf20Sopenharmony_ci test_flag = ABIT_UGURU_VOLT_LOW_ALARM_FLAG; 5168c2ecf20Sopenharmony_ci } else { 5178c2ecf20Sopenharmony_ci buf[0] = ABIT_UGURU_VOLT_HIGH_ALARM_ENABLE; 5188c2ecf20Sopenharmony_ci buf[1] = 5; 5198c2ecf20Sopenharmony_ci buf[2] = 10; 5208c2ecf20Sopenharmony_ci test_flag = ABIT_UGURU_VOLT_HIGH_ALARM_FLAG; 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr, 5248c2ecf20Sopenharmony_ci buf, 3) != 3) 5258c2ecf20Sopenharmony_ci goto abituguru_detect_bank1_sensor_type_exit; 5268c2ecf20Sopenharmony_ci /* 5278c2ecf20Sopenharmony_ci * Now we need 20 ms to give the uguru time to read the sensors 5288c2ecf20Sopenharmony_ci * and raise a voltage alarm 5298c2ecf20Sopenharmony_ci */ 5308c2ecf20Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 5318c2ecf20Sopenharmony_ci schedule_timeout(HZ/50); 5328c2ecf20Sopenharmony_ci /* Check for alarm and check the alarm is a volt low alarm. */ 5338c2ecf20Sopenharmony_ci if (abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0, buf, 3, 5348c2ecf20Sopenharmony_ci ABIT_UGURU_MAX_RETRIES) != 3) 5358c2ecf20Sopenharmony_ci goto abituguru_detect_bank1_sensor_type_exit; 5368c2ecf20Sopenharmony_ci if (buf[sensor_addr/8] & (0x01 << (sensor_addr % 8))) { 5378c2ecf20Sopenharmony_ci if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1 + 1, 5388c2ecf20Sopenharmony_ci sensor_addr, buf, 3, 5398c2ecf20Sopenharmony_ci ABIT_UGURU_MAX_RETRIES) != 3) 5408c2ecf20Sopenharmony_ci goto abituguru_detect_bank1_sensor_type_exit; 5418c2ecf20Sopenharmony_ci if (buf[0] & test_flag) { 5428c2ecf20Sopenharmony_ci ABIT_UGURU_DEBUG(2, " found volt sensor\n"); 5438c2ecf20Sopenharmony_ci ret = ABIT_UGURU_IN_SENSOR; 5448c2ecf20Sopenharmony_ci goto abituguru_detect_bank1_sensor_type_exit; 5458c2ecf20Sopenharmony_ci } else 5468c2ecf20Sopenharmony_ci ABIT_UGURU_DEBUG(2, " alarm raised during volt " 5478c2ecf20Sopenharmony_ci "sensor test, but volt range flag not set\n"); 5488c2ecf20Sopenharmony_ci } else 5498c2ecf20Sopenharmony_ci ABIT_UGURU_DEBUG(2, " alarm not raised during volt sensor " 5508c2ecf20Sopenharmony_ci "test\n"); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci /* 5538c2ecf20Sopenharmony_ci * Temp sensor test, enable sensor as a temp sensor, set beep value 5548c2ecf20Sopenharmony_ci * ridiculously low (but not too low, otherwise uguru ignores it). 5558c2ecf20Sopenharmony_ci * If its a temp sensor this should always give us an alarm. 5568c2ecf20Sopenharmony_ci */ 5578c2ecf20Sopenharmony_ci buf[0] = ABIT_UGURU_TEMP_HIGH_ALARM_ENABLE; 5588c2ecf20Sopenharmony_ci buf[1] = 5; 5598c2ecf20Sopenharmony_ci buf[2] = 10; 5608c2ecf20Sopenharmony_ci if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, sensor_addr, 5618c2ecf20Sopenharmony_ci buf, 3) != 3) 5628c2ecf20Sopenharmony_ci goto abituguru_detect_bank1_sensor_type_exit; 5638c2ecf20Sopenharmony_ci /* 5648c2ecf20Sopenharmony_ci * Now we need 50 ms to give the uguru time to read the sensors 5658c2ecf20Sopenharmony_ci * and raise a temp alarm 5668c2ecf20Sopenharmony_ci */ 5678c2ecf20Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 5688c2ecf20Sopenharmony_ci schedule_timeout(HZ/20); 5698c2ecf20Sopenharmony_ci /* Check for alarm and check the alarm is a temp high alarm. */ 5708c2ecf20Sopenharmony_ci if (abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0, buf, 3, 5718c2ecf20Sopenharmony_ci ABIT_UGURU_MAX_RETRIES) != 3) 5728c2ecf20Sopenharmony_ci goto abituguru_detect_bank1_sensor_type_exit; 5738c2ecf20Sopenharmony_ci if (buf[sensor_addr/8] & (0x01 << (sensor_addr % 8))) { 5748c2ecf20Sopenharmony_ci if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1 + 1, 5758c2ecf20Sopenharmony_ci sensor_addr, buf, 3, 5768c2ecf20Sopenharmony_ci ABIT_UGURU_MAX_RETRIES) != 3) 5778c2ecf20Sopenharmony_ci goto abituguru_detect_bank1_sensor_type_exit; 5788c2ecf20Sopenharmony_ci if (buf[0] & ABIT_UGURU_TEMP_HIGH_ALARM_FLAG) { 5798c2ecf20Sopenharmony_ci ABIT_UGURU_DEBUG(2, " found temp sensor\n"); 5808c2ecf20Sopenharmony_ci ret = ABIT_UGURU_TEMP_SENSOR; 5818c2ecf20Sopenharmony_ci goto abituguru_detect_bank1_sensor_type_exit; 5828c2ecf20Sopenharmony_ci } else 5838c2ecf20Sopenharmony_ci ABIT_UGURU_DEBUG(2, " alarm raised during temp " 5848c2ecf20Sopenharmony_ci "sensor test, but temp high flag not set\n"); 5858c2ecf20Sopenharmony_ci } else 5868c2ecf20Sopenharmony_ci ABIT_UGURU_DEBUG(2, " alarm not raised during temp sensor " 5878c2ecf20Sopenharmony_ci "test\n"); 5888c2ecf20Sopenharmony_ci 5898c2ecf20Sopenharmony_ci ret = ABIT_UGURU_NC; 5908c2ecf20Sopenharmony_ciabituguru_detect_bank1_sensor_type_exit: 5918c2ecf20Sopenharmony_ci /* 5928c2ecf20Sopenharmony_ci * Restore original settings, failing here is really BAD, it has been 5938c2ecf20Sopenharmony_ci * reported that some BIOS-es hang when entering the uGuru menu with 5948c2ecf20Sopenharmony_ci * invalid settings present in the uGuru, so we try this 3 times. 5958c2ecf20Sopenharmony_ci */ 5968c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) 5978c2ecf20Sopenharmony_ci if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, 5988c2ecf20Sopenharmony_ci sensor_addr, data->bank1_settings[sensor_addr], 5998c2ecf20Sopenharmony_ci 3) == 3) 6008c2ecf20Sopenharmony_ci break; 6018c2ecf20Sopenharmony_ci if (i == 3) { 6028c2ecf20Sopenharmony_ci pr_err("Fatal error could not restore original settings. %s %s\n", 6038c2ecf20Sopenharmony_ci never_happen, report_this); 6048c2ecf20Sopenharmony_ci return -ENODEV; 6058c2ecf20Sopenharmony_ci } 6068c2ecf20Sopenharmony_ci return ret; 6078c2ecf20Sopenharmony_ci} 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci/* 6108c2ecf20Sopenharmony_ci * These functions try to find out how many sensors there are in bank2 and how 6118c2ecf20Sopenharmony_ci * many pwms there are. The purpose of this is to make sure that we don't give 6128c2ecf20Sopenharmony_ci * the user the possibility to change settings for non-existent sensors / pwm. 6138c2ecf20Sopenharmony_ci * The uGuru will happily read / write whatever memory happens to be after the 6148c2ecf20Sopenharmony_ci * memory storing the PWM settings when reading/writing to a PWM which is not 6158c2ecf20Sopenharmony_ci * there. Notice even if we detect a PWM which doesn't exist we normally won't 6168c2ecf20Sopenharmony_ci * write to it, unless the user tries to change the settings. 6178c2ecf20Sopenharmony_ci * 6188c2ecf20Sopenharmony_ci * Although the uGuru allows reading (settings) from non existing bank2 6198c2ecf20Sopenharmony_ci * sensors, my version of the uGuru does seem to stop writing to them, the 6208c2ecf20Sopenharmony_ci * write function above aborts in this case with: 6218c2ecf20Sopenharmony_ci * "CMD reg does not hold 0xAC after write" 6228c2ecf20Sopenharmony_ci * 6238c2ecf20Sopenharmony_ci * Notice these 2 tests are non destructive iow read-only tests, otherwise 6248c2ecf20Sopenharmony_ci * they would defeat their purpose. Although for the bank2_sensors detection a 6258c2ecf20Sopenharmony_ci * read/write test would be feasible because of the reaction above, I've 6268c2ecf20Sopenharmony_ci * however opted to stay on the safe side. 6278c2ecf20Sopenharmony_ci */ 6288c2ecf20Sopenharmony_cistatic void 6298c2ecf20Sopenharmony_ciabituguru_detect_no_bank2_sensors(struct abituguru_data *data) 6308c2ecf20Sopenharmony_ci{ 6318c2ecf20Sopenharmony_ci int i; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci if (fan_sensors > 0 && fan_sensors <= ABIT_UGURU_MAX_BANK2_SENSORS) { 6348c2ecf20Sopenharmony_ci data->bank2_sensors = fan_sensors; 6358c2ecf20Sopenharmony_ci ABIT_UGURU_DEBUG(2, "assuming %d fan sensors because of " 6368c2ecf20Sopenharmony_ci "\"fan_sensors\" module param\n", 6378c2ecf20Sopenharmony_ci (int)data->bank2_sensors); 6388c2ecf20Sopenharmony_ci return; 6398c2ecf20Sopenharmony_ci } 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci ABIT_UGURU_DEBUG(2, "detecting number of fan sensors\n"); 6428c2ecf20Sopenharmony_ci for (i = 0; i < ABIT_UGURU_MAX_BANK2_SENSORS; i++) { 6438c2ecf20Sopenharmony_ci /* 6448c2ecf20Sopenharmony_ci * 0x89 are the known used bits: 6458c2ecf20Sopenharmony_ci * -0x80 enable shutdown 6468c2ecf20Sopenharmony_ci * -0x08 enable beep 6478c2ecf20Sopenharmony_ci * -0x01 enable alarm 6488c2ecf20Sopenharmony_ci * All other bits should be 0, but on some motherboards 6498c2ecf20Sopenharmony_ci * 0x40 (bit 6) is also high for some of the fans?? 6508c2ecf20Sopenharmony_ci */ 6518c2ecf20Sopenharmony_ci if (data->bank2_settings[i][0] & ~0xC9) { 6528c2ecf20Sopenharmony_ci ABIT_UGURU_DEBUG(2, " bank2 sensor %d does not seem " 6538c2ecf20Sopenharmony_ci "to be a fan sensor: settings[0] = %02X\n", 6548c2ecf20Sopenharmony_ci i, (unsigned int)data->bank2_settings[i][0]); 6558c2ecf20Sopenharmony_ci break; 6568c2ecf20Sopenharmony_ci } 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci /* check if the threshold is within the allowed range */ 6598c2ecf20Sopenharmony_ci if (data->bank2_settings[i][1] < 6608c2ecf20Sopenharmony_ci abituguru_bank2_min_threshold) { 6618c2ecf20Sopenharmony_ci ABIT_UGURU_DEBUG(2, " bank2 sensor %d does not seem " 6628c2ecf20Sopenharmony_ci "to be a fan sensor: the threshold (%d) is " 6638c2ecf20Sopenharmony_ci "below the minimum (%d)\n", i, 6648c2ecf20Sopenharmony_ci (int)data->bank2_settings[i][1], 6658c2ecf20Sopenharmony_ci (int)abituguru_bank2_min_threshold); 6668c2ecf20Sopenharmony_ci break; 6678c2ecf20Sopenharmony_ci } 6688c2ecf20Sopenharmony_ci if (data->bank2_settings[i][1] > 6698c2ecf20Sopenharmony_ci abituguru_bank2_max_threshold) { 6708c2ecf20Sopenharmony_ci ABIT_UGURU_DEBUG(2, " bank2 sensor %d does not seem " 6718c2ecf20Sopenharmony_ci "to be a fan sensor: the threshold (%d) is " 6728c2ecf20Sopenharmony_ci "above the maximum (%d)\n", i, 6738c2ecf20Sopenharmony_ci (int)data->bank2_settings[i][1], 6748c2ecf20Sopenharmony_ci (int)abituguru_bank2_max_threshold); 6758c2ecf20Sopenharmony_ci break; 6768c2ecf20Sopenharmony_ci } 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci data->bank2_sensors = i; 6808c2ecf20Sopenharmony_ci ABIT_UGURU_DEBUG(2, " found: %d fan sensors\n", 6818c2ecf20Sopenharmony_ci (int)data->bank2_sensors); 6828c2ecf20Sopenharmony_ci} 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_cistatic void 6858c2ecf20Sopenharmony_ciabituguru_detect_no_pwms(struct abituguru_data *data) 6868c2ecf20Sopenharmony_ci{ 6878c2ecf20Sopenharmony_ci int i, j; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci if (pwms > 0 && pwms <= ABIT_UGURU_MAX_PWMS) { 6908c2ecf20Sopenharmony_ci data->pwms = pwms; 6918c2ecf20Sopenharmony_ci ABIT_UGURU_DEBUG(2, "assuming %d PWM outputs because of " 6928c2ecf20Sopenharmony_ci "\"pwms\" module param\n", (int)data->pwms); 6938c2ecf20Sopenharmony_ci return; 6948c2ecf20Sopenharmony_ci } 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci ABIT_UGURU_DEBUG(2, "detecting number of PWM outputs\n"); 6978c2ecf20Sopenharmony_ci for (i = 0; i < ABIT_UGURU_MAX_PWMS; i++) { 6988c2ecf20Sopenharmony_ci /* 6998c2ecf20Sopenharmony_ci * 0x80 is the enable bit and the low 7008c2ecf20Sopenharmony_ci * nibble is which temp sensor to use, 7018c2ecf20Sopenharmony_ci * the other bits should be 0 7028c2ecf20Sopenharmony_ci */ 7038c2ecf20Sopenharmony_ci if (data->pwm_settings[i][0] & ~0x8F) { 7048c2ecf20Sopenharmony_ci ABIT_UGURU_DEBUG(2, " pwm channel %d does not seem " 7058c2ecf20Sopenharmony_ci "to be a pwm channel: settings[0] = %02X\n", 7068c2ecf20Sopenharmony_ci i, (unsigned int)data->pwm_settings[i][0]); 7078c2ecf20Sopenharmony_ci break; 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci /* 7118c2ecf20Sopenharmony_ci * the low nibble must correspond to one of the temp sensors 7128c2ecf20Sopenharmony_ci * we've found 7138c2ecf20Sopenharmony_ci */ 7148c2ecf20Sopenharmony_ci for (j = 0; j < data->bank1_sensors[ABIT_UGURU_TEMP_SENSOR]; 7158c2ecf20Sopenharmony_ci j++) { 7168c2ecf20Sopenharmony_ci if (data->bank1_address[ABIT_UGURU_TEMP_SENSOR][j] == 7178c2ecf20Sopenharmony_ci (data->pwm_settings[i][0] & 0x0F)) 7188c2ecf20Sopenharmony_ci break; 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci if (j == data->bank1_sensors[ABIT_UGURU_TEMP_SENSOR]) { 7218c2ecf20Sopenharmony_ci ABIT_UGURU_DEBUG(2, " pwm channel %d does not seem " 7228c2ecf20Sopenharmony_ci "to be a pwm channel: %d is not a valid temp " 7238c2ecf20Sopenharmony_ci "sensor address\n", i, 7248c2ecf20Sopenharmony_ci data->pwm_settings[i][0] & 0x0F); 7258c2ecf20Sopenharmony_ci break; 7268c2ecf20Sopenharmony_ci } 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci /* check if all other settings are within the allowed range */ 7298c2ecf20Sopenharmony_ci for (j = 1; j < 5; j++) { 7308c2ecf20Sopenharmony_ci u8 min; 7318c2ecf20Sopenharmony_ci /* special case pwm1 min pwm% */ 7328c2ecf20Sopenharmony_ci if ((i == 0) && ((j == 1) || (j == 2))) 7338c2ecf20Sopenharmony_ci min = 77; 7348c2ecf20Sopenharmony_ci else 7358c2ecf20Sopenharmony_ci min = abituguru_pwm_min[j]; 7368c2ecf20Sopenharmony_ci if (data->pwm_settings[i][j] < min) { 7378c2ecf20Sopenharmony_ci ABIT_UGURU_DEBUG(2, " pwm channel %d does " 7388c2ecf20Sopenharmony_ci "not seem to be a pwm channel: " 7398c2ecf20Sopenharmony_ci "setting %d (%d) is below the minimum " 7408c2ecf20Sopenharmony_ci "value (%d)\n", i, j, 7418c2ecf20Sopenharmony_ci (int)data->pwm_settings[i][j], 7428c2ecf20Sopenharmony_ci (int)min); 7438c2ecf20Sopenharmony_ci goto abituguru_detect_no_pwms_exit; 7448c2ecf20Sopenharmony_ci } 7458c2ecf20Sopenharmony_ci if (data->pwm_settings[i][j] > abituguru_pwm_max[j]) { 7468c2ecf20Sopenharmony_ci ABIT_UGURU_DEBUG(2, " pwm channel %d does " 7478c2ecf20Sopenharmony_ci "not seem to be a pwm channel: " 7488c2ecf20Sopenharmony_ci "setting %d (%d) is above the maximum " 7498c2ecf20Sopenharmony_ci "value (%d)\n", i, j, 7508c2ecf20Sopenharmony_ci (int)data->pwm_settings[i][j], 7518c2ecf20Sopenharmony_ci (int)abituguru_pwm_max[j]); 7528c2ecf20Sopenharmony_ci goto abituguru_detect_no_pwms_exit; 7538c2ecf20Sopenharmony_ci } 7548c2ecf20Sopenharmony_ci } 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci /* check that min temp < max temp and min pwm < max pwm */ 7578c2ecf20Sopenharmony_ci if (data->pwm_settings[i][1] >= data->pwm_settings[i][2]) { 7588c2ecf20Sopenharmony_ci ABIT_UGURU_DEBUG(2, " pwm channel %d does not seem " 7598c2ecf20Sopenharmony_ci "to be a pwm channel: min pwm (%d) >= " 7608c2ecf20Sopenharmony_ci "max pwm (%d)\n", i, 7618c2ecf20Sopenharmony_ci (int)data->pwm_settings[i][1], 7628c2ecf20Sopenharmony_ci (int)data->pwm_settings[i][2]); 7638c2ecf20Sopenharmony_ci break; 7648c2ecf20Sopenharmony_ci } 7658c2ecf20Sopenharmony_ci if (data->pwm_settings[i][3] >= data->pwm_settings[i][4]) { 7668c2ecf20Sopenharmony_ci ABIT_UGURU_DEBUG(2, " pwm channel %d does not seem " 7678c2ecf20Sopenharmony_ci "to be a pwm channel: min temp (%d) >= " 7688c2ecf20Sopenharmony_ci "max temp (%d)\n", i, 7698c2ecf20Sopenharmony_ci (int)data->pwm_settings[i][3], 7708c2ecf20Sopenharmony_ci (int)data->pwm_settings[i][4]); 7718c2ecf20Sopenharmony_ci break; 7728c2ecf20Sopenharmony_ci } 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ciabituguru_detect_no_pwms_exit: 7768c2ecf20Sopenharmony_ci data->pwms = i; 7778c2ecf20Sopenharmony_ci ABIT_UGURU_DEBUG(2, " found: %d PWM outputs\n", (int)data->pwms); 7788c2ecf20Sopenharmony_ci} 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci/* 7818c2ecf20Sopenharmony_ci * Following are the sysfs callback functions. These functions expect: 7828c2ecf20Sopenharmony_ci * sensor_device_attribute_2->index: sensor address/offset in the bank 7838c2ecf20Sopenharmony_ci * sensor_device_attribute_2->nr: register offset, bitmask or NA. 7848c2ecf20Sopenharmony_ci */ 7858c2ecf20Sopenharmony_cistatic struct abituguru_data *abituguru_update_device(struct device *dev); 7868c2ecf20Sopenharmony_ci 7878c2ecf20Sopenharmony_cistatic ssize_t show_bank1_value(struct device *dev, 7888c2ecf20Sopenharmony_ci struct device_attribute *devattr, char *buf) 7898c2ecf20Sopenharmony_ci{ 7908c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); 7918c2ecf20Sopenharmony_ci struct abituguru_data *data = abituguru_update_device(dev); 7928c2ecf20Sopenharmony_ci if (!data) 7938c2ecf20Sopenharmony_ci return -EIO; 7948c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", (data->bank1_value[attr->index] * 7958c2ecf20Sopenharmony_ci data->bank1_max_value[attr->index] + 128) / 255); 7968c2ecf20Sopenharmony_ci} 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_cistatic ssize_t show_bank1_setting(struct device *dev, 7998c2ecf20Sopenharmony_ci struct device_attribute *devattr, char *buf) 8008c2ecf20Sopenharmony_ci{ 8018c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); 8028c2ecf20Sopenharmony_ci struct abituguru_data *data = dev_get_drvdata(dev); 8038c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", 8048c2ecf20Sopenharmony_ci (data->bank1_settings[attr->index][attr->nr] * 8058c2ecf20Sopenharmony_ci data->bank1_max_value[attr->index] + 128) / 255); 8068c2ecf20Sopenharmony_ci} 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_cistatic ssize_t show_bank2_value(struct device *dev, 8098c2ecf20Sopenharmony_ci struct device_attribute *devattr, char *buf) 8108c2ecf20Sopenharmony_ci{ 8118c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); 8128c2ecf20Sopenharmony_ci struct abituguru_data *data = abituguru_update_device(dev); 8138c2ecf20Sopenharmony_ci if (!data) 8148c2ecf20Sopenharmony_ci return -EIO; 8158c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", (data->bank2_value[attr->index] * 8168c2ecf20Sopenharmony_ci ABIT_UGURU_FAN_MAX + 128) / 255); 8178c2ecf20Sopenharmony_ci} 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_cistatic ssize_t show_bank2_setting(struct device *dev, 8208c2ecf20Sopenharmony_ci struct device_attribute *devattr, char *buf) 8218c2ecf20Sopenharmony_ci{ 8228c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); 8238c2ecf20Sopenharmony_ci struct abituguru_data *data = dev_get_drvdata(dev); 8248c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", 8258c2ecf20Sopenharmony_ci (data->bank2_settings[attr->index][attr->nr] * 8268c2ecf20Sopenharmony_ci ABIT_UGURU_FAN_MAX + 128) / 255); 8278c2ecf20Sopenharmony_ci} 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_cistatic ssize_t store_bank1_setting(struct device *dev, struct device_attribute 8308c2ecf20Sopenharmony_ci *devattr, const char *buf, size_t count) 8318c2ecf20Sopenharmony_ci{ 8328c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); 8338c2ecf20Sopenharmony_ci struct abituguru_data *data = dev_get_drvdata(dev); 8348c2ecf20Sopenharmony_ci unsigned long val; 8358c2ecf20Sopenharmony_ci ssize_t ret; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci ret = kstrtoul(buf, 10, &val); 8388c2ecf20Sopenharmony_ci if (ret) 8398c2ecf20Sopenharmony_ci return ret; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci ret = count; 8428c2ecf20Sopenharmony_ci val = (val * 255 + data->bank1_max_value[attr->index] / 2) / 8438c2ecf20Sopenharmony_ci data->bank1_max_value[attr->index]; 8448c2ecf20Sopenharmony_ci if (val > 255) 8458c2ecf20Sopenharmony_ci return -EINVAL; 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 8488c2ecf20Sopenharmony_ci if (data->bank1_settings[attr->index][attr->nr] != val) { 8498c2ecf20Sopenharmony_ci u8 orig_val = data->bank1_settings[attr->index][attr->nr]; 8508c2ecf20Sopenharmony_ci data->bank1_settings[attr->index][attr->nr] = val; 8518c2ecf20Sopenharmony_ci if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK1 + 2, 8528c2ecf20Sopenharmony_ci attr->index, data->bank1_settings[attr->index], 8538c2ecf20Sopenharmony_ci 3) <= attr->nr) { 8548c2ecf20Sopenharmony_ci data->bank1_settings[attr->index][attr->nr] = orig_val; 8558c2ecf20Sopenharmony_ci ret = -EIO; 8568c2ecf20Sopenharmony_ci } 8578c2ecf20Sopenharmony_ci } 8588c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 8598c2ecf20Sopenharmony_ci return ret; 8608c2ecf20Sopenharmony_ci} 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_cistatic ssize_t store_bank2_setting(struct device *dev, struct device_attribute 8638c2ecf20Sopenharmony_ci *devattr, const char *buf, size_t count) 8648c2ecf20Sopenharmony_ci{ 8658c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); 8668c2ecf20Sopenharmony_ci struct abituguru_data *data = dev_get_drvdata(dev); 8678c2ecf20Sopenharmony_ci unsigned long val; 8688c2ecf20Sopenharmony_ci ssize_t ret; 8698c2ecf20Sopenharmony_ci 8708c2ecf20Sopenharmony_ci ret = kstrtoul(buf, 10, &val); 8718c2ecf20Sopenharmony_ci if (ret) 8728c2ecf20Sopenharmony_ci return ret; 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci ret = count; 8758c2ecf20Sopenharmony_ci val = (val * 255 + ABIT_UGURU_FAN_MAX / 2) / ABIT_UGURU_FAN_MAX; 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci /* this check can be done before taking the lock */ 8788c2ecf20Sopenharmony_ci if (val < abituguru_bank2_min_threshold || 8798c2ecf20Sopenharmony_ci val > abituguru_bank2_max_threshold) 8808c2ecf20Sopenharmony_ci return -EINVAL; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 8838c2ecf20Sopenharmony_ci if (data->bank2_settings[attr->index][attr->nr] != val) { 8848c2ecf20Sopenharmony_ci u8 orig_val = data->bank2_settings[attr->index][attr->nr]; 8858c2ecf20Sopenharmony_ci data->bank2_settings[attr->index][attr->nr] = val; 8868c2ecf20Sopenharmony_ci if (abituguru_write(data, ABIT_UGURU_SENSOR_BANK2 + 2, 8878c2ecf20Sopenharmony_ci attr->index, data->bank2_settings[attr->index], 8888c2ecf20Sopenharmony_ci 2) <= attr->nr) { 8898c2ecf20Sopenharmony_ci data->bank2_settings[attr->index][attr->nr] = orig_val; 8908c2ecf20Sopenharmony_ci ret = -EIO; 8918c2ecf20Sopenharmony_ci } 8928c2ecf20Sopenharmony_ci } 8938c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 8948c2ecf20Sopenharmony_ci return ret; 8958c2ecf20Sopenharmony_ci} 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_cistatic ssize_t show_bank1_alarm(struct device *dev, 8988c2ecf20Sopenharmony_ci struct device_attribute *devattr, char *buf) 8998c2ecf20Sopenharmony_ci{ 9008c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); 9018c2ecf20Sopenharmony_ci struct abituguru_data *data = abituguru_update_device(dev); 9028c2ecf20Sopenharmony_ci if (!data) 9038c2ecf20Sopenharmony_ci return -EIO; 9048c2ecf20Sopenharmony_ci /* 9058c2ecf20Sopenharmony_ci * See if the alarm bit for this sensor is set, and if the 9068c2ecf20Sopenharmony_ci * alarm matches the type of alarm we're looking for (for volt 9078c2ecf20Sopenharmony_ci * it can be either low or high). The type is stored in a few 9088c2ecf20Sopenharmony_ci * readonly bits in the settings part of the relevant sensor. 9098c2ecf20Sopenharmony_ci * The bitmask of the type is passed to us in attr->nr. 9108c2ecf20Sopenharmony_ci */ 9118c2ecf20Sopenharmony_ci if ((data->alarms[attr->index / 8] & (0x01 << (attr->index % 8))) && 9128c2ecf20Sopenharmony_ci (data->bank1_settings[attr->index][0] & attr->nr)) 9138c2ecf20Sopenharmony_ci return sprintf(buf, "1\n"); 9148c2ecf20Sopenharmony_ci else 9158c2ecf20Sopenharmony_ci return sprintf(buf, "0\n"); 9168c2ecf20Sopenharmony_ci} 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_cistatic ssize_t show_bank2_alarm(struct device *dev, 9198c2ecf20Sopenharmony_ci struct device_attribute *devattr, char *buf) 9208c2ecf20Sopenharmony_ci{ 9218c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); 9228c2ecf20Sopenharmony_ci struct abituguru_data *data = abituguru_update_device(dev); 9238c2ecf20Sopenharmony_ci if (!data) 9248c2ecf20Sopenharmony_ci return -EIO; 9258c2ecf20Sopenharmony_ci if (data->alarms[2] & (0x01 << attr->index)) 9268c2ecf20Sopenharmony_ci return sprintf(buf, "1\n"); 9278c2ecf20Sopenharmony_ci else 9288c2ecf20Sopenharmony_ci return sprintf(buf, "0\n"); 9298c2ecf20Sopenharmony_ci} 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_cistatic ssize_t show_bank1_mask(struct device *dev, 9328c2ecf20Sopenharmony_ci struct device_attribute *devattr, char *buf) 9338c2ecf20Sopenharmony_ci{ 9348c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); 9358c2ecf20Sopenharmony_ci struct abituguru_data *data = dev_get_drvdata(dev); 9368c2ecf20Sopenharmony_ci if (data->bank1_settings[attr->index][0] & attr->nr) 9378c2ecf20Sopenharmony_ci return sprintf(buf, "1\n"); 9388c2ecf20Sopenharmony_ci else 9398c2ecf20Sopenharmony_ci return sprintf(buf, "0\n"); 9408c2ecf20Sopenharmony_ci} 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_cistatic ssize_t show_bank2_mask(struct device *dev, 9438c2ecf20Sopenharmony_ci struct device_attribute *devattr, char *buf) 9448c2ecf20Sopenharmony_ci{ 9458c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); 9468c2ecf20Sopenharmony_ci struct abituguru_data *data = dev_get_drvdata(dev); 9478c2ecf20Sopenharmony_ci if (data->bank2_settings[attr->index][0] & attr->nr) 9488c2ecf20Sopenharmony_ci return sprintf(buf, "1\n"); 9498c2ecf20Sopenharmony_ci else 9508c2ecf20Sopenharmony_ci return sprintf(buf, "0\n"); 9518c2ecf20Sopenharmony_ci} 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_cistatic ssize_t store_bank1_mask(struct device *dev, 9548c2ecf20Sopenharmony_ci struct device_attribute *devattr, const char *buf, size_t count) 9558c2ecf20Sopenharmony_ci{ 9568c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); 9578c2ecf20Sopenharmony_ci struct abituguru_data *data = dev_get_drvdata(dev); 9588c2ecf20Sopenharmony_ci ssize_t ret; 9598c2ecf20Sopenharmony_ci u8 orig_val; 9608c2ecf20Sopenharmony_ci unsigned long mask; 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci ret = kstrtoul(buf, 10, &mask); 9638c2ecf20Sopenharmony_ci if (ret) 9648c2ecf20Sopenharmony_ci return ret; 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci ret = count; 9678c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 9688c2ecf20Sopenharmony_ci orig_val = data->bank1_settings[attr->index][0]; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci if (mask) 9718c2ecf20Sopenharmony_ci data->bank1_settings[attr->index][0] |= attr->nr; 9728c2ecf20Sopenharmony_ci else 9738c2ecf20Sopenharmony_ci data->bank1_settings[attr->index][0] &= ~attr->nr; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci if ((data->bank1_settings[attr->index][0] != orig_val) && 9768c2ecf20Sopenharmony_ci (abituguru_write(data, 9778c2ecf20Sopenharmony_ci ABIT_UGURU_SENSOR_BANK1 + 2, attr->index, 9788c2ecf20Sopenharmony_ci data->bank1_settings[attr->index], 3) < 1)) { 9798c2ecf20Sopenharmony_ci data->bank1_settings[attr->index][0] = orig_val; 9808c2ecf20Sopenharmony_ci ret = -EIO; 9818c2ecf20Sopenharmony_ci } 9828c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 9838c2ecf20Sopenharmony_ci return ret; 9848c2ecf20Sopenharmony_ci} 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_cistatic ssize_t store_bank2_mask(struct device *dev, 9878c2ecf20Sopenharmony_ci struct device_attribute *devattr, const char *buf, size_t count) 9888c2ecf20Sopenharmony_ci{ 9898c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); 9908c2ecf20Sopenharmony_ci struct abituguru_data *data = dev_get_drvdata(dev); 9918c2ecf20Sopenharmony_ci ssize_t ret; 9928c2ecf20Sopenharmony_ci u8 orig_val; 9938c2ecf20Sopenharmony_ci unsigned long mask; 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci ret = kstrtoul(buf, 10, &mask); 9968c2ecf20Sopenharmony_ci if (ret) 9978c2ecf20Sopenharmony_ci return ret; 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci ret = count; 10008c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 10018c2ecf20Sopenharmony_ci orig_val = data->bank2_settings[attr->index][0]; 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci if (mask) 10048c2ecf20Sopenharmony_ci data->bank2_settings[attr->index][0] |= attr->nr; 10058c2ecf20Sopenharmony_ci else 10068c2ecf20Sopenharmony_ci data->bank2_settings[attr->index][0] &= ~attr->nr; 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci if ((data->bank2_settings[attr->index][0] != orig_val) && 10098c2ecf20Sopenharmony_ci (abituguru_write(data, 10108c2ecf20Sopenharmony_ci ABIT_UGURU_SENSOR_BANK2 + 2, attr->index, 10118c2ecf20Sopenharmony_ci data->bank2_settings[attr->index], 2) < 1)) { 10128c2ecf20Sopenharmony_ci data->bank2_settings[attr->index][0] = orig_val; 10138c2ecf20Sopenharmony_ci ret = -EIO; 10148c2ecf20Sopenharmony_ci } 10158c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 10168c2ecf20Sopenharmony_ci return ret; 10178c2ecf20Sopenharmony_ci} 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci/* Fan PWM (speed control) */ 10208c2ecf20Sopenharmony_cistatic ssize_t show_pwm_setting(struct device *dev, 10218c2ecf20Sopenharmony_ci struct device_attribute *devattr, char *buf) 10228c2ecf20Sopenharmony_ci{ 10238c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); 10248c2ecf20Sopenharmony_ci struct abituguru_data *data = dev_get_drvdata(dev); 10258c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", data->pwm_settings[attr->index][attr->nr] * 10268c2ecf20Sopenharmony_ci abituguru_pwm_settings_multiplier[attr->nr]); 10278c2ecf20Sopenharmony_ci} 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_cistatic ssize_t store_pwm_setting(struct device *dev, struct device_attribute 10308c2ecf20Sopenharmony_ci *devattr, const char *buf, size_t count) 10318c2ecf20Sopenharmony_ci{ 10328c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); 10338c2ecf20Sopenharmony_ci struct abituguru_data *data = dev_get_drvdata(dev); 10348c2ecf20Sopenharmony_ci u8 min; 10358c2ecf20Sopenharmony_ci unsigned long val; 10368c2ecf20Sopenharmony_ci ssize_t ret; 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_ci ret = kstrtoul(buf, 10, &val); 10398c2ecf20Sopenharmony_ci if (ret) 10408c2ecf20Sopenharmony_ci return ret; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci ret = count; 10438c2ecf20Sopenharmony_ci val = (val + abituguru_pwm_settings_multiplier[attr->nr] / 2) / 10448c2ecf20Sopenharmony_ci abituguru_pwm_settings_multiplier[attr->nr]; 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci /* special case pwm1 min pwm% */ 10478c2ecf20Sopenharmony_ci if ((attr->index == 0) && ((attr->nr == 1) || (attr->nr == 2))) 10488c2ecf20Sopenharmony_ci min = 77; 10498c2ecf20Sopenharmony_ci else 10508c2ecf20Sopenharmony_ci min = abituguru_pwm_min[attr->nr]; 10518c2ecf20Sopenharmony_ci 10528c2ecf20Sopenharmony_ci /* this check can be done before taking the lock */ 10538c2ecf20Sopenharmony_ci if (val < min || val > abituguru_pwm_max[attr->nr]) 10548c2ecf20Sopenharmony_ci return -EINVAL; 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 10578c2ecf20Sopenharmony_ci /* this check needs to be done after taking the lock */ 10588c2ecf20Sopenharmony_ci if ((attr->nr & 1) && 10598c2ecf20Sopenharmony_ci (val >= data->pwm_settings[attr->index][attr->nr + 1])) 10608c2ecf20Sopenharmony_ci ret = -EINVAL; 10618c2ecf20Sopenharmony_ci else if (!(attr->nr & 1) && 10628c2ecf20Sopenharmony_ci (val <= data->pwm_settings[attr->index][attr->nr - 1])) 10638c2ecf20Sopenharmony_ci ret = -EINVAL; 10648c2ecf20Sopenharmony_ci else if (data->pwm_settings[attr->index][attr->nr] != val) { 10658c2ecf20Sopenharmony_ci u8 orig_val = data->pwm_settings[attr->index][attr->nr]; 10668c2ecf20Sopenharmony_ci data->pwm_settings[attr->index][attr->nr] = val; 10678c2ecf20Sopenharmony_ci if (abituguru_write(data, ABIT_UGURU_FAN_PWM + 1, 10688c2ecf20Sopenharmony_ci attr->index, data->pwm_settings[attr->index], 10698c2ecf20Sopenharmony_ci 5) <= attr->nr) { 10708c2ecf20Sopenharmony_ci data->pwm_settings[attr->index][attr->nr] = 10718c2ecf20Sopenharmony_ci orig_val; 10728c2ecf20Sopenharmony_ci ret = -EIO; 10738c2ecf20Sopenharmony_ci } 10748c2ecf20Sopenharmony_ci } 10758c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 10768c2ecf20Sopenharmony_ci return ret; 10778c2ecf20Sopenharmony_ci} 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_cistatic ssize_t show_pwm_sensor(struct device *dev, 10808c2ecf20Sopenharmony_ci struct device_attribute *devattr, char *buf) 10818c2ecf20Sopenharmony_ci{ 10828c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); 10838c2ecf20Sopenharmony_ci struct abituguru_data *data = dev_get_drvdata(dev); 10848c2ecf20Sopenharmony_ci int i; 10858c2ecf20Sopenharmony_ci /* 10868c2ecf20Sopenharmony_ci * We need to walk to the temp sensor addresses to find what 10878c2ecf20Sopenharmony_ci * the userspace id of the configured temp sensor is. 10888c2ecf20Sopenharmony_ci */ 10898c2ecf20Sopenharmony_ci for (i = 0; i < data->bank1_sensors[ABIT_UGURU_TEMP_SENSOR]; i++) 10908c2ecf20Sopenharmony_ci if (data->bank1_address[ABIT_UGURU_TEMP_SENSOR][i] == 10918c2ecf20Sopenharmony_ci (data->pwm_settings[attr->index][0] & 0x0F)) 10928c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", i+1); 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci return -ENXIO; 10958c2ecf20Sopenharmony_ci} 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_cistatic ssize_t store_pwm_sensor(struct device *dev, struct device_attribute 10988c2ecf20Sopenharmony_ci *devattr, const char *buf, size_t count) 10998c2ecf20Sopenharmony_ci{ 11008c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); 11018c2ecf20Sopenharmony_ci struct abituguru_data *data = dev_get_drvdata(dev); 11028c2ecf20Sopenharmony_ci ssize_t ret; 11038c2ecf20Sopenharmony_ci unsigned long val; 11048c2ecf20Sopenharmony_ci u8 orig_val; 11058c2ecf20Sopenharmony_ci u8 address; 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci ret = kstrtoul(buf, 10, &val); 11088c2ecf20Sopenharmony_ci if (ret) 11098c2ecf20Sopenharmony_ci return ret; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci if (val == 0 || val > data->bank1_sensors[ABIT_UGURU_TEMP_SENSOR]) 11128c2ecf20Sopenharmony_ci return -EINVAL; 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci val -= 1; 11158c2ecf20Sopenharmony_ci ret = count; 11168c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 11178c2ecf20Sopenharmony_ci orig_val = data->pwm_settings[attr->index][0]; 11188c2ecf20Sopenharmony_ci address = data->bank1_address[ABIT_UGURU_TEMP_SENSOR][val]; 11198c2ecf20Sopenharmony_ci data->pwm_settings[attr->index][0] &= 0xF0; 11208c2ecf20Sopenharmony_ci data->pwm_settings[attr->index][0] |= address; 11218c2ecf20Sopenharmony_ci if (data->pwm_settings[attr->index][0] != orig_val) { 11228c2ecf20Sopenharmony_ci if (abituguru_write(data, ABIT_UGURU_FAN_PWM + 1, attr->index, 11238c2ecf20Sopenharmony_ci data->pwm_settings[attr->index], 5) < 1) { 11248c2ecf20Sopenharmony_ci data->pwm_settings[attr->index][0] = orig_val; 11258c2ecf20Sopenharmony_ci ret = -EIO; 11268c2ecf20Sopenharmony_ci } 11278c2ecf20Sopenharmony_ci } 11288c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 11298c2ecf20Sopenharmony_ci return ret; 11308c2ecf20Sopenharmony_ci} 11318c2ecf20Sopenharmony_ci 11328c2ecf20Sopenharmony_cistatic ssize_t show_pwm_enable(struct device *dev, 11338c2ecf20Sopenharmony_ci struct device_attribute *devattr, char *buf) 11348c2ecf20Sopenharmony_ci{ 11358c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); 11368c2ecf20Sopenharmony_ci struct abituguru_data *data = dev_get_drvdata(dev); 11378c2ecf20Sopenharmony_ci int res = 0; 11388c2ecf20Sopenharmony_ci if (data->pwm_settings[attr->index][0] & ABIT_UGURU_FAN_PWM_ENABLE) 11398c2ecf20Sopenharmony_ci res = 2; 11408c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", res); 11418c2ecf20Sopenharmony_ci} 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_cistatic ssize_t store_pwm_enable(struct device *dev, struct device_attribute 11448c2ecf20Sopenharmony_ci *devattr, const char *buf, size_t count) 11458c2ecf20Sopenharmony_ci{ 11468c2ecf20Sopenharmony_ci struct sensor_device_attribute_2 *attr = to_sensor_dev_attr_2(devattr); 11478c2ecf20Sopenharmony_ci struct abituguru_data *data = dev_get_drvdata(dev); 11488c2ecf20Sopenharmony_ci u8 orig_val; 11498c2ecf20Sopenharmony_ci ssize_t ret; 11508c2ecf20Sopenharmony_ci unsigned long user_val; 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci ret = kstrtoul(buf, 10, &user_val); 11538c2ecf20Sopenharmony_ci if (ret) 11548c2ecf20Sopenharmony_ci return ret; 11558c2ecf20Sopenharmony_ci 11568c2ecf20Sopenharmony_ci ret = count; 11578c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 11588c2ecf20Sopenharmony_ci orig_val = data->pwm_settings[attr->index][0]; 11598c2ecf20Sopenharmony_ci switch (user_val) { 11608c2ecf20Sopenharmony_ci case 0: 11618c2ecf20Sopenharmony_ci data->pwm_settings[attr->index][0] &= 11628c2ecf20Sopenharmony_ci ~ABIT_UGURU_FAN_PWM_ENABLE; 11638c2ecf20Sopenharmony_ci break; 11648c2ecf20Sopenharmony_ci case 2: 11658c2ecf20Sopenharmony_ci data->pwm_settings[attr->index][0] |= ABIT_UGURU_FAN_PWM_ENABLE; 11668c2ecf20Sopenharmony_ci break; 11678c2ecf20Sopenharmony_ci default: 11688c2ecf20Sopenharmony_ci ret = -EINVAL; 11698c2ecf20Sopenharmony_ci } 11708c2ecf20Sopenharmony_ci if ((data->pwm_settings[attr->index][0] != orig_val) && 11718c2ecf20Sopenharmony_ci (abituguru_write(data, ABIT_UGURU_FAN_PWM + 1, 11728c2ecf20Sopenharmony_ci attr->index, data->pwm_settings[attr->index], 11738c2ecf20Sopenharmony_ci 5) < 1)) { 11748c2ecf20Sopenharmony_ci data->pwm_settings[attr->index][0] = orig_val; 11758c2ecf20Sopenharmony_ci ret = -EIO; 11768c2ecf20Sopenharmony_ci } 11778c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 11788c2ecf20Sopenharmony_ci return ret; 11798c2ecf20Sopenharmony_ci} 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_cistatic ssize_t show_name(struct device *dev, 11828c2ecf20Sopenharmony_ci struct device_attribute *devattr, char *buf) 11838c2ecf20Sopenharmony_ci{ 11848c2ecf20Sopenharmony_ci return sprintf(buf, "%s\n", ABIT_UGURU_NAME); 11858c2ecf20Sopenharmony_ci} 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci/* Sysfs attr templates, the real entries are generated automatically. */ 11888c2ecf20Sopenharmony_cistatic const 11898c2ecf20Sopenharmony_cistruct sensor_device_attribute_2 abituguru_sysfs_bank1_templ[2][9] = { 11908c2ecf20Sopenharmony_ci { 11918c2ecf20Sopenharmony_ci SENSOR_ATTR_2(in%d_input, 0444, show_bank1_value, NULL, 0, 0), 11928c2ecf20Sopenharmony_ci SENSOR_ATTR_2(in%d_min, 0644, show_bank1_setting, 11938c2ecf20Sopenharmony_ci store_bank1_setting, 1, 0), 11948c2ecf20Sopenharmony_ci SENSOR_ATTR_2(in%d_min_alarm, 0444, show_bank1_alarm, NULL, 11958c2ecf20Sopenharmony_ci ABIT_UGURU_VOLT_LOW_ALARM_FLAG, 0), 11968c2ecf20Sopenharmony_ci SENSOR_ATTR_2(in%d_max, 0644, show_bank1_setting, 11978c2ecf20Sopenharmony_ci store_bank1_setting, 2, 0), 11988c2ecf20Sopenharmony_ci SENSOR_ATTR_2(in%d_max_alarm, 0444, show_bank1_alarm, NULL, 11998c2ecf20Sopenharmony_ci ABIT_UGURU_VOLT_HIGH_ALARM_FLAG, 0), 12008c2ecf20Sopenharmony_ci SENSOR_ATTR_2(in%d_beep, 0644, show_bank1_mask, 12018c2ecf20Sopenharmony_ci store_bank1_mask, ABIT_UGURU_BEEP_ENABLE, 0), 12028c2ecf20Sopenharmony_ci SENSOR_ATTR_2(in%d_shutdown, 0644, show_bank1_mask, 12038c2ecf20Sopenharmony_ci store_bank1_mask, ABIT_UGURU_SHUTDOWN_ENABLE, 0), 12048c2ecf20Sopenharmony_ci SENSOR_ATTR_2(in%d_min_alarm_enable, 0644, show_bank1_mask, 12058c2ecf20Sopenharmony_ci store_bank1_mask, ABIT_UGURU_VOLT_LOW_ALARM_ENABLE, 0), 12068c2ecf20Sopenharmony_ci SENSOR_ATTR_2(in%d_max_alarm_enable, 0644, show_bank1_mask, 12078c2ecf20Sopenharmony_ci store_bank1_mask, ABIT_UGURU_VOLT_HIGH_ALARM_ENABLE, 0), 12088c2ecf20Sopenharmony_ci }, { 12098c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp%d_input, 0444, show_bank1_value, NULL, 0, 0), 12108c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp%d_alarm, 0444, show_bank1_alarm, NULL, 12118c2ecf20Sopenharmony_ci ABIT_UGURU_TEMP_HIGH_ALARM_FLAG, 0), 12128c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp%d_max, 0644, show_bank1_setting, 12138c2ecf20Sopenharmony_ci store_bank1_setting, 1, 0), 12148c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp%d_crit, 0644, show_bank1_setting, 12158c2ecf20Sopenharmony_ci store_bank1_setting, 2, 0), 12168c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp%d_beep, 0644, show_bank1_mask, 12178c2ecf20Sopenharmony_ci store_bank1_mask, ABIT_UGURU_BEEP_ENABLE, 0), 12188c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp%d_shutdown, 0644, show_bank1_mask, 12198c2ecf20Sopenharmony_ci store_bank1_mask, ABIT_UGURU_SHUTDOWN_ENABLE, 0), 12208c2ecf20Sopenharmony_ci SENSOR_ATTR_2(temp%d_alarm_enable, 0644, show_bank1_mask, 12218c2ecf20Sopenharmony_ci store_bank1_mask, ABIT_UGURU_TEMP_HIGH_ALARM_ENABLE, 0), 12228c2ecf20Sopenharmony_ci } 12238c2ecf20Sopenharmony_ci}; 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_cistatic const struct sensor_device_attribute_2 abituguru_sysfs_fan_templ[6] = { 12268c2ecf20Sopenharmony_ci SENSOR_ATTR_2(fan%d_input, 0444, show_bank2_value, NULL, 0, 0), 12278c2ecf20Sopenharmony_ci SENSOR_ATTR_2(fan%d_alarm, 0444, show_bank2_alarm, NULL, 0, 0), 12288c2ecf20Sopenharmony_ci SENSOR_ATTR_2(fan%d_min, 0644, show_bank2_setting, 12298c2ecf20Sopenharmony_ci store_bank2_setting, 1, 0), 12308c2ecf20Sopenharmony_ci SENSOR_ATTR_2(fan%d_beep, 0644, show_bank2_mask, 12318c2ecf20Sopenharmony_ci store_bank2_mask, ABIT_UGURU_BEEP_ENABLE, 0), 12328c2ecf20Sopenharmony_ci SENSOR_ATTR_2(fan%d_shutdown, 0644, show_bank2_mask, 12338c2ecf20Sopenharmony_ci store_bank2_mask, ABIT_UGURU_SHUTDOWN_ENABLE, 0), 12348c2ecf20Sopenharmony_ci SENSOR_ATTR_2(fan%d_alarm_enable, 0644, show_bank2_mask, 12358c2ecf20Sopenharmony_ci store_bank2_mask, ABIT_UGURU_FAN_LOW_ALARM_ENABLE, 0), 12368c2ecf20Sopenharmony_ci}; 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_cistatic const struct sensor_device_attribute_2 abituguru_sysfs_pwm_templ[6] = { 12398c2ecf20Sopenharmony_ci SENSOR_ATTR_2(pwm%d_enable, 0644, show_pwm_enable, 12408c2ecf20Sopenharmony_ci store_pwm_enable, 0, 0), 12418c2ecf20Sopenharmony_ci SENSOR_ATTR_2(pwm%d_auto_channels_temp, 0644, show_pwm_sensor, 12428c2ecf20Sopenharmony_ci store_pwm_sensor, 0, 0), 12438c2ecf20Sopenharmony_ci SENSOR_ATTR_2(pwm%d_auto_point1_pwm, 0644, show_pwm_setting, 12448c2ecf20Sopenharmony_ci store_pwm_setting, 1, 0), 12458c2ecf20Sopenharmony_ci SENSOR_ATTR_2(pwm%d_auto_point2_pwm, 0644, show_pwm_setting, 12468c2ecf20Sopenharmony_ci store_pwm_setting, 2, 0), 12478c2ecf20Sopenharmony_ci SENSOR_ATTR_2(pwm%d_auto_point1_temp, 0644, show_pwm_setting, 12488c2ecf20Sopenharmony_ci store_pwm_setting, 3, 0), 12498c2ecf20Sopenharmony_ci SENSOR_ATTR_2(pwm%d_auto_point2_temp, 0644, show_pwm_setting, 12508c2ecf20Sopenharmony_ci store_pwm_setting, 4, 0), 12518c2ecf20Sopenharmony_ci}; 12528c2ecf20Sopenharmony_ci 12538c2ecf20Sopenharmony_cistatic struct sensor_device_attribute_2 abituguru_sysfs_attr[] = { 12548c2ecf20Sopenharmony_ci SENSOR_ATTR_2(name, 0444, show_name, NULL, 0, 0), 12558c2ecf20Sopenharmony_ci}; 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_cistatic int abituguru_probe(struct platform_device *pdev) 12588c2ecf20Sopenharmony_ci{ 12598c2ecf20Sopenharmony_ci struct abituguru_data *data; 12608c2ecf20Sopenharmony_ci int i, j, used, sysfs_names_free, sysfs_attr_i, res = -ENODEV; 12618c2ecf20Sopenharmony_ci char *sysfs_filename; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci /* 12648c2ecf20Sopenharmony_ci * El weirdo probe order, to keep the sysfs order identical to the 12658c2ecf20Sopenharmony_ci * BIOS and window-appliction listing order. 12668c2ecf20Sopenharmony_ci */ 12678c2ecf20Sopenharmony_ci static const u8 probe_order[ABIT_UGURU_MAX_BANK1_SENSORS] = { 12688c2ecf20Sopenharmony_ci 0x00, 0x01, 0x03, 0x04, 0x0A, 0x08, 0x0E, 0x02, 12698c2ecf20Sopenharmony_ci 0x09, 0x06, 0x05, 0x0B, 0x0F, 0x0D, 0x07, 0x0C }; 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci data = devm_kzalloc(&pdev->dev, sizeof(struct abituguru_data), 12728c2ecf20Sopenharmony_ci GFP_KERNEL); 12738c2ecf20Sopenharmony_ci if (!data) 12748c2ecf20Sopenharmony_ci return -ENOMEM; 12758c2ecf20Sopenharmony_ci 12768c2ecf20Sopenharmony_ci data->addr = platform_get_resource(pdev, IORESOURCE_IO, 0)->start; 12778c2ecf20Sopenharmony_ci mutex_init(&data->update_lock); 12788c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, data); 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci /* See if the uGuru is ready */ 12818c2ecf20Sopenharmony_ci if (inb_p(data->addr + ABIT_UGURU_DATA) == ABIT_UGURU_STATUS_INPUT) 12828c2ecf20Sopenharmony_ci data->uguru_ready = 1; 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci /* 12858c2ecf20Sopenharmony_ci * Completely read the uGuru this has 2 purposes: 12868c2ecf20Sopenharmony_ci * - testread / see if one really is there. 12878c2ecf20Sopenharmony_ci * - make an in memory copy of all the uguru settings for future use. 12888c2ecf20Sopenharmony_ci */ 12898c2ecf20Sopenharmony_ci if (abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0, 12908c2ecf20Sopenharmony_ci data->alarms, 3, ABIT_UGURU_MAX_RETRIES) != 3) 12918c2ecf20Sopenharmony_ci goto abituguru_probe_error; 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_ci for (i = 0; i < ABIT_UGURU_MAX_BANK1_SENSORS; i++) { 12948c2ecf20Sopenharmony_ci if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1, i, 12958c2ecf20Sopenharmony_ci &data->bank1_value[i], 1, 12968c2ecf20Sopenharmony_ci ABIT_UGURU_MAX_RETRIES) != 1) 12978c2ecf20Sopenharmony_ci goto abituguru_probe_error; 12988c2ecf20Sopenharmony_ci if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK1+1, i, 12998c2ecf20Sopenharmony_ci data->bank1_settings[i], 3, 13008c2ecf20Sopenharmony_ci ABIT_UGURU_MAX_RETRIES) != 3) 13018c2ecf20Sopenharmony_ci goto abituguru_probe_error; 13028c2ecf20Sopenharmony_ci } 13038c2ecf20Sopenharmony_ci /* 13048c2ecf20Sopenharmony_ci * Note: We don't know how many bank2 sensors / pwms there really are, 13058c2ecf20Sopenharmony_ci * but in order to "detect" this we need to read the maximum amount 13068c2ecf20Sopenharmony_ci * anyways. If we read sensors/pwms not there we'll just read crap 13078c2ecf20Sopenharmony_ci * this can't hurt. We need the detection because we don't want 13088c2ecf20Sopenharmony_ci * unwanted writes, which will hurt! 13098c2ecf20Sopenharmony_ci */ 13108c2ecf20Sopenharmony_ci for (i = 0; i < ABIT_UGURU_MAX_BANK2_SENSORS; i++) { 13118c2ecf20Sopenharmony_ci if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK2, i, 13128c2ecf20Sopenharmony_ci &data->bank2_value[i], 1, 13138c2ecf20Sopenharmony_ci ABIT_UGURU_MAX_RETRIES) != 1) 13148c2ecf20Sopenharmony_ci goto abituguru_probe_error; 13158c2ecf20Sopenharmony_ci if (abituguru_read(data, ABIT_UGURU_SENSOR_BANK2+1, i, 13168c2ecf20Sopenharmony_ci data->bank2_settings[i], 2, 13178c2ecf20Sopenharmony_ci ABIT_UGURU_MAX_RETRIES) != 2) 13188c2ecf20Sopenharmony_ci goto abituguru_probe_error; 13198c2ecf20Sopenharmony_ci } 13208c2ecf20Sopenharmony_ci for (i = 0; i < ABIT_UGURU_MAX_PWMS; i++) { 13218c2ecf20Sopenharmony_ci if (abituguru_read(data, ABIT_UGURU_FAN_PWM, i, 13228c2ecf20Sopenharmony_ci data->pwm_settings[i], 5, 13238c2ecf20Sopenharmony_ci ABIT_UGURU_MAX_RETRIES) != 5) 13248c2ecf20Sopenharmony_ci goto abituguru_probe_error; 13258c2ecf20Sopenharmony_ci } 13268c2ecf20Sopenharmony_ci data->last_updated = jiffies; 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci /* Detect sensor types and fill the sysfs attr for bank1 */ 13298c2ecf20Sopenharmony_ci sysfs_attr_i = 0; 13308c2ecf20Sopenharmony_ci sysfs_filename = data->sysfs_names; 13318c2ecf20Sopenharmony_ci sysfs_names_free = ABITUGURU_SYSFS_NAMES_LENGTH; 13328c2ecf20Sopenharmony_ci for (i = 0; i < ABIT_UGURU_MAX_BANK1_SENSORS; i++) { 13338c2ecf20Sopenharmony_ci res = abituguru_detect_bank1_sensor_type(data, probe_order[i]); 13348c2ecf20Sopenharmony_ci if (res < 0) 13358c2ecf20Sopenharmony_ci goto abituguru_probe_error; 13368c2ecf20Sopenharmony_ci if (res == ABIT_UGURU_NC) 13378c2ecf20Sopenharmony_ci continue; 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_ci /* res 1 (temp) sensors have 7 sysfs entries, 0 (in) 9 */ 13408c2ecf20Sopenharmony_ci for (j = 0; j < (res ? 7 : 9); j++) { 13418c2ecf20Sopenharmony_ci used = snprintf(sysfs_filename, sysfs_names_free, 13428c2ecf20Sopenharmony_ci abituguru_sysfs_bank1_templ[res][j].dev_attr. 13438c2ecf20Sopenharmony_ci attr.name, data->bank1_sensors[res] + res) 13448c2ecf20Sopenharmony_ci + 1; 13458c2ecf20Sopenharmony_ci data->sysfs_attr[sysfs_attr_i] = 13468c2ecf20Sopenharmony_ci abituguru_sysfs_bank1_templ[res][j]; 13478c2ecf20Sopenharmony_ci data->sysfs_attr[sysfs_attr_i].dev_attr.attr.name = 13488c2ecf20Sopenharmony_ci sysfs_filename; 13498c2ecf20Sopenharmony_ci data->sysfs_attr[sysfs_attr_i].index = probe_order[i]; 13508c2ecf20Sopenharmony_ci sysfs_filename += used; 13518c2ecf20Sopenharmony_ci sysfs_names_free -= used; 13528c2ecf20Sopenharmony_ci sysfs_attr_i++; 13538c2ecf20Sopenharmony_ci } 13548c2ecf20Sopenharmony_ci data->bank1_max_value[probe_order[i]] = 13558c2ecf20Sopenharmony_ci abituguru_bank1_max_value[res]; 13568c2ecf20Sopenharmony_ci data->bank1_address[res][data->bank1_sensors[res]] = 13578c2ecf20Sopenharmony_ci probe_order[i]; 13588c2ecf20Sopenharmony_ci data->bank1_sensors[res]++; 13598c2ecf20Sopenharmony_ci } 13608c2ecf20Sopenharmony_ci /* Detect number of sensors and fill the sysfs attr for bank2 (fans) */ 13618c2ecf20Sopenharmony_ci abituguru_detect_no_bank2_sensors(data); 13628c2ecf20Sopenharmony_ci for (i = 0; i < data->bank2_sensors; i++) { 13638c2ecf20Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(abituguru_sysfs_fan_templ); j++) { 13648c2ecf20Sopenharmony_ci used = snprintf(sysfs_filename, sysfs_names_free, 13658c2ecf20Sopenharmony_ci abituguru_sysfs_fan_templ[j].dev_attr.attr.name, 13668c2ecf20Sopenharmony_ci i + 1) + 1; 13678c2ecf20Sopenharmony_ci data->sysfs_attr[sysfs_attr_i] = 13688c2ecf20Sopenharmony_ci abituguru_sysfs_fan_templ[j]; 13698c2ecf20Sopenharmony_ci data->sysfs_attr[sysfs_attr_i].dev_attr.attr.name = 13708c2ecf20Sopenharmony_ci sysfs_filename; 13718c2ecf20Sopenharmony_ci data->sysfs_attr[sysfs_attr_i].index = i; 13728c2ecf20Sopenharmony_ci sysfs_filename += used; 13738c2ecf20Sopenharmony_ci sysfs_names_free -= used; 13748c2ecf20Sopenharmony_ci sysfs_attr_i++; 13758c2ecf20Sopenharmony_ci } 13768c2ecf20Sopenharmony_ci } 13778c2ecf20Sopenharmony_ci /* Detect number of sensors and fill the sysfs attr for pwms */ 13788c2ecf20Sopenharmony_ci abituguru_detect_no_pwms(data); 13798c2ecf20Sopenharmony_ci for (i = 0; i < data->pwms; i++) { 13808c2ecf20Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(abituguru_sysfs_pwm_templ); j++) { 13818c2ecf20Sopenharmony_ci used = snprintf(sysfs_filename, sysfs_names_free, 13828c2ecf20Sopenharmony_ci abituguru_sysfs_pwm_templ[j].dev_attr.attr.name, 13838c2ecf20Sopenharmony_ci i + 1) + 1; 13848c2ecf20Sopenharmony_ci data->sysfs_attr[sysfs_attr_i] = 13858c2ecf20Sopenharmony_ci abituguru_sysfs_pwm_templ[j]; 13868c2ecf20Sopenharmony_ci data->sysfs_attr[sysfs_attr_i].dev_attr.attr.name = 13878c2ecf20Sopenharmony_ci sysfs_filename; 13888c2ecf20Sopenharmony_ci data->sysfs_attr[sysfs_attr_i].index = i; 13898c2ecf20Sopenharmony_ci sysfs_filename += used; 13908c2ecf20Sopenharmony_ci sysfs_names_free -= used; 13918c2ecf20Sopenharmony_ci sysfs_attr_i++; 13928c2ecf20Sopenharmony_ci } 13938c2ecf20Sopenharmony_ci } 13948c2ecf20Sopenharmony_ci /* Fail safe check, this should never happen! */ 13958c2ecf20Sopenharmony_ci if (sysfs_names_free < 0) { 13968c2ecf20Sopenharmony_ci pr_err("Fatal error ran out of space for sysfs attr names. %s %s", 13978c2ecf20Sopenharmony_ci never_happen, report_this); 13988c2ecf20Sopenharmony_ci res = -ENAMETOOLONG; 13998c2ecf20Sopenharmony_ci goto abituguru_probe_error; 14008c2ecf20Sopenharmony_ci } 14018c2ecf20Sopenharmony_ci pr_info("found Abit uGuru\n"); 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci /* Register sysfs hooks */ 14048c2ecf20Sopenharmony_ci for (i = 0; i < sysfs_attr_i; i++) { 14058c2ecf20Sopenharmony_ci res = device_create_file(&pdev->dev, 14068c2ecf20Sopenharmony_ci &data->sysfs_attr[i].dev_attr); 14078c2ecf20Sopenharmony_ci if (res) 14088c2ecf20Sopenharmony_ci goto abituguru_probe_error; 14098c2ecf20Sopenharmony_ci } 14108c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++) { 14118c2ecf20Sopenharmony_ci res = device_create_file(&pdev->dev, 14128c2ecf20Sopenharmony_ci &abituguru_sysfs_attr[i].dev_attr); 14138c2ecf20Sopenharmony_ci if (res) 14148c2ecf20Sopenharmony_ci goto abituguru_probe_error; 14158c2ecf20Sopenharmony_ci } 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci data->hwmon_dev = hwmon_device_register(&pdev->dev); 14188c2ecf20Sopenharmony_ci if (!IS_ERR(data->hwmon_dev)) 14198c2ecf20Sopenharmony_ci return 0; /* success */ 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci res = PTR_ERR(data->hwmon_dev); 14228c2ecf20Sopenharmony_ciabituguru_probe_error: 14238c2ecf20Sopenharmony_ci for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++) 14248c2ecf20Sopenharmony_ci device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr); 14258c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++) 14268c2ecf20Sopenharmony_ci device_remove_file(&pdev->dev, 14278c2ecf20Sopenharmony_ci &abituguru_sysfs_attr[i].dev_attr); 14288c2ecf20Sopenharmony_ci return res; 14298c2ecf20Sopenharmony_ci} 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_cistatic int abituguru_remove(struct platform_device *pdev) 14328c2ecf20Sopenharmony_ci{ 14338c2ecf20Sopenharmony_ci int i; 14348c2ecf20Sopenharmony_ci struct abituguru_data *data = platform_get_drvdata(pdev); 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci hwmon_device_unregister(data->hwmon_dev); 14378c2ecf20Sopenharmony_ci for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++) 14388c2ecf20Sopenharmony_ci device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr); 14398c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++) 14408c2ecf20Sopenharmony_ci device_remove_file(&pdev->dev, 14418c2ecf20Sopenharmony_ci &abituguru_sysfs_attr[i].dev_attr); 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci return 0; 14448c2ecf20Sopenharmony_ci} 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_cistatic struct abituguru_data *abituguru_update_device(struct device *dev) 14478c2ecf20Sopenharmony_ci{ 14488c2ecf20Sopenharmony_ci int i, err; 14498c2ecf20Sopenharmony_ci struct abituguru_data *data = dev_get_drvdata(dev); 14508c2ecf20Sopenharmony_ci /* fake a complete successful read if no update necessary. */ 14518c2ecf20Sopenharmony_ci char success = 1; 14528c2ecf20Sopenharmony_ci 14538c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 14548c2ecf20Sopenharmony_ci if (time_after(jiffies, data->last_updated + HZ)) { 14558c2ecf20Sopenharmony_ci success = 0; 14568c2ecf20Sopenharmony_ci err = abituguru_read(data, ABIT_UGURU_ALARM_BANK, 0, 14578c2ecf20Sopenharmony_ci data->alarms, 3, 0); 14588c2ecf20Sopenharmony_ci if (err != 3) 14598c2ecf20Sopenharmony_ci goto LEAVE_UPDATE; 14608c2ecf20Sopenharmony_ci for (i = 0; i < ABIT_UGURU_MAX_BANK1_SENSORS; i++) { 14618c2ecf20Sopenharmony_ci err = abituguru_read(data, ABIT_UGURU_SENSOR_BANK1, 14628c2ecf20Sopenharmony_ci i, &data->bank1_value[i], 1, 0); 14638c2ecf20Sopenharmony_ci if (err != 1) 14648c2ecf20Sopenharmony_ci goto LEAVE_UPDATE; 14658c2ecf20Sopenharmony_ci err = abituguru_read(data, ABIT_UGURU_SENSOR_BANK1 + 1, 14668c2ecf20Sopenharmony_ci i, data->bank1_settings[i], 3, 0); 14678c2ecf20Sopenharmony_ci if (err != 3) 14688c2ecf20Sopenharmony_ci goto LEAVE_UPDATE; 14698c2ecf20Sopenharmony_ci } 14708c2ecf20Sopenharmony_ci for (i = 0; i < data->bank2_sensors; i++) { 14718c2ecf20Sopenharmony_ci err = abituguru_read(data, ABIT_UGURU_SENSOR_BANK2, i, 14728c2ecf20Sopenharmony_ci &data->bank2_value[i], 1, 0); 14738c2ecf20Sopenharmony_ci if (err != 1) 14748c2ecf20Sopenharmony_ci goto LEAVE_UPDATE; 14758c2ecf20Sopenharmony_ci } 14768c2ecf20Sopenharmony_ci /* success! */ 14778c2ecf20Sopenharmony_ci success = 1; 14788c2ecf20Sopenharmony_ci data->update_timeouts = 0; 14798c2ecf20Sopenharmony_ciLEAVE_UPDATE: 14808c2ecf20Sopenharmony_ci /* handle timeout condition */ 14818c2ecf20Sopenharmony_ci if (!success && (err == -EBUSY || err >= 0)) { 14828c2ecf20Sopenharmony_ci /* No overflow please */ 14838c2ecf20Sopenharmony_ci if (data->update_timeouts < 255u) 14848c2ecf20Sopenharmony_ci data->update_timeouts++; 14858c2ecf20Sopenharmony_ci if (data->update_timeouts <= ABIT_UGURU_MAX_TIMEOUTS) { 14868c2ecf20Sopenharmony_ci ABIT_UGURU_DEBUG(3, "timeout exceeded, will " 14878c2ecf20Sopenharmony_ci "try again next update\n"); 14888c2ecf20Sopenharmony_ci /* Just a timeout, fake a successful read */ 14898c2ecf20Sopenharmony_ci success = 1; 14908c2ecf20Sopenharmony_ci } else 14918c2ecf20Sopenharmony_ci ABIT_UGURU_DEBUG(1, "timeout exceeded %d " 14928c2ecf20Sopenharmony_ci "times waiting for more input state\n", 14938c2ecf20Sopenharmony_ci (int)data->update_timeouts); 14948c2ecf20Sopenharmony_ci } 14958c2ecf20Sopenharmony_ci /* On success set last_updated */ 14968c2ecf20Sopenharmony_ci if (success) 14978c2ecf20Sopenharmony_ci data->last_updated = jiffies; 14988c2ecf20Sopenharmony_ci } 14998c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci if (success) 15028c2ecf20Sopenharmony_ci return data; 15038c2ecf20Sopenharmony_ci else 15048c2ecf20Sopenharmony_ci return NULL; 15058c2ecf20Sopenharmony_ci} 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 15088c2ecf20Sopenharmony_cistatic int abituguru_suspend(struct device *dev) 15098c2ecf20Sopenharmony_ci{ 15108c2ecf20Sopenharmony_ci struct abituguru_data *data = dev_get_drvdata(dev); 15118c2ecf20Sopenharmony_ci /* 15128c2ecf20Sopenharmony_ci * make sure all communications with the uguru are done and no new 15138c2ecf20Sopenharmony_ci * ones are started 15148c2ecf20Sopenharmony_ci */ 15158c2ecf20Sopenharmony_ci mutex_lock(&data->update_lock); 15168c2ecf20Sopenharmony_ci return 0; 15178c2ecf20Sopenharmony_ci} 15188c2ecf20Sopenharmony_ci 15198c2ecf20Sopenharmony_cistatic int abituguru_resume(struct device *dev) 15208c2ecf20Sopenharmony_ci{ 15218c2ecf20Sopenharmony_ci struct abituguru_data *data = dev_get_drvdata(dev); 15228c2ecf20Sopenharmony_ci /* See if the uGuru is still ready */ 15238c2ecf20Sopenharmony_ci if (inb_p(data->addr + ABIT_UGURU_DATA) != ABIT_UGURU_STATUS_INPUT) 15248c2ecf20Sopenharmony_ci data->uguru_ready = 0; 15258c2ecf20Sopenharmony_ci mutex_unlock(&data->update_lock); 15268c2ecf20Sopenharmony_ci return 0; 15278c2ecf20Sopenharmony_ci} 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(abituguru_pm, abituguru_suspend, abituguru_resume); 15308c2ecf20Sopenharmony_ci#define ABIT_UGURU_PM (&abituguru_pm) 15318c2ecf20Sopenharmony_ci#else 15328c2ecf20Sopenharmony_ci#define ABIT_UGURU_PM NULL 15338c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */ 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_cistatic struct platform_driver abituguru_driver = { 15368c2ecf20Sopenharmony_ci .driver = { 15378c2ecf20Sopenharmony_ci .name = ABIT_UGURU_NAME, 15388c2ecf20Sopenharmony_ci .pm = ABIT_UGURU_PM, 15398c2ecf20Sopenharmony_ci }, 15408c2ecf20Sopenharmony_ci .probe = abituguru_probe, 15418c2ecf20Sopenharmony_ci .remove = abituguru_remove, 15428c2ecf20Sopenharmony_ci}; 15438c2ecf20Sopenharmony_ci 15448c2ecf20Sopenharmony_cistatic int __init abituguru_detect(void) 15458c2ecf20Sopenharmony_ci{ 15468c2ecf20Sopenharmony_ci /* 15478c2ecf20Sopenharmony_ci * See if there is an uguru there. After a reboot uGuru will hold 0x00 15488c2ecf20Sopenharmony_ci * at DATA and 0xAC, when this driver has already been loaded once 15498c2ecf20Sopenharmony_ci * DATA will hold 0x08. For most uGuru's CMD will hold 0xAC in either 15508c2ecf20Sopenharmony_ci * scenario but some will hold 0x00. 15518c2ecf20Sopenharmony_ci * Some uGuru's initially hold 0x09 at DATA and will only hold 0x08 15528c2ecf20Sopenharmony_ci * after reading CMD first, so CMD must be read first! 15538c2ecf20Sopenharmony_ci */ 15548c2ecf20Sopenharmony_ci u8 cmd_val = inb_p(ABIT_UGURU_BASE + ABIT_UGURU_CMD); 15558c2ecf20Sopenharmony_ci u8 data_val = inb_p(ABIT_UGURU_BASE + ABIT_UGURU_DATA); 15568c2ecf20Sopenharmony_ci if (((data_val == 0x00) || (data_val == 0x08)) && 15578c2ecf20Sopenharmony_ci ((cmd_val == 0x00) || (cmd_val == 0xAC))) 15588c2ecf20Sopenharmony_ci return ABIT_UGURU_BASE; 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_ci ABIT_UGURU_DEBUG(2, "no Abit uGuru found, data = 0x%02X, cmd = " 15618c2ecf20Sopenharmony_ci "0x%02X\n", (unsigned int)data_val, (unsigned int)cmd_val); 15628c2ecf20Sopenharmony_ci 15638c2ecf20Sopenharmony_ci if (force) { 15648c2ecf20Sopenharmony_ci pr_info("Assuming Abit uGuru is present because of \"force\" parameter\n"); 15658c2ecf20Sopenharmony_ci return ABIT_UGURU_BASE; 15668c2ecf20Sopenharmony_ci } 15678c2ecf20Sopenharmony_ci 15688c2ecf20Sopenharmony_ci /* No uGuru found */ 15698c2ecf20Sopenharmony_ci return -ENODEV; 15708c2ecf20Sopenharmony_ci} 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_cistatic struct platform_device *abituguru_pdev; 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_cistatic int __init abituguru_init(void) 15758c2ecf20Sopenharmony_ci{ 15768c2ecf20Sopenharmony_ci int address, err; 15778c2ecf20Sopenharmony_ci struct resource res = { .flags = IORESOURCE_IO }; 15788c2ecf20Sopenharmony_ci const char *board_vendor = dmi_get_system_info(DMI_BOARD_VENDOR); 15798c2ecf20Sopenharmony_ci 15808c2ecf20Sopenharmony_ci /* safety check, refuse to load on non Abit motherboards */ 15818c2ecf20Sopenharmony_ci if (!force && (!board_vendor || 15828c2ecf20Sopenharmony_ci strcmp(board_vendor, "http://www.abit.com.tw/"))) 15838c2ecf20Sopenharmony_ci return -ENODEV; 15848c2ecf20Sopenharmony_ci 15858c2ecf20Sopenharmony_ci address = abituguru_detect(); 15868c2ecf20Sopenharmony_ci if (address < 0) 15878c2ecf20Sopenharmony_ci return address; 15888c2ecf20Sopenharmony_ci 15898c2ecf20Sopenharmony_ci err = platform_driver_register(&abituguru_driver); 15908c2ecf20Sopenharmony_ci if (err) 15918c2ecf20Sopenharmony_ci goto exit; 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_ci abituguru_pdev = platform_device_alloc(ABIT_UGURU_NAME, address); 15948c2ecf20Sopenharmony_ci if (!abituguru_pdev) { 15958c2ecf20Sopenharmony_ci pr_err("Device allocation failed\n"); 15968c2ecf20Sopenharmony_ci err = -ENOMEM; 15978c2ecf20Sopenharmony_ci goto exit_driver_unregister; 15988c2ecf20Sopenharmony_ci } 15998c2ecf20Sopenharmony_ci 16008c2ecf20Sopenharmony_ci res.start = address; 16018c2ecf20Sopenharmony_ci res.end = address + ABIT_UGURU_REGION_LENGTH - 1; 16028c2ecf20Sopenharmony_ci res.name = ABIT_UGURU_NAME; 16038c2ecf20Sopenharmony_ci 16048c2ecf20Sopenharmony_ci err = platform_device_add_resources(abituguru_pdev, &res, 1); 16058c2ecf20Sopenharmony_ci if (err) { 16068c2ecf20Sopenharmony_ci pr_err("Device resource addition failed (%d)\n", err); 16078c2ecf20Sopenharmony_ci goto exit_device_put; 16088c2ecf20Sopenharmony_ci } 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci err = platform_device_add(abituguru_pdev); 16118c2ecf20Sopenharmony_ci if (err) { 16128c2ecf20Sopenharmony_ci pr_err("Device addition failed (%d)\n", err); 16138c2ecf20Sopenharmony_ci goto exit_device_put; 16148c2ecf20Sopenharmony_ci } 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ci return 0; 16178c2ecf20Sopenharmony_ci 16188c2ecf20Sopenharmony_ciexit_device_put: 16198c2ecf20Sopenharmony_ci platform_device_put(abituguru_pdev); 16208c2ecf20Sopenharmony_ciexit_driver_unregister: 16218c2ecf20Sopenharmony_ci platform_driver_unregister(&abituguru_driver); 16228c2ecf20Sopenharmony_ciexit: 16238c2ecf20Sopenharmony_ci return err; 16248c2ecf20Sopenharmony_ci} 16258c2ecf20Sopenharmony_ci 16268c2ecf20Sopenharmony_cistatic void __exit abituguru_exit(void) 16278c2ecf20Sopenharmony_ci{ 16288c2ecf20Sopenharmony_ci platform_device_unregister(abituguru_pdev); 16298c2ecf20Sopenharmony_ci platform_driver_unregister(&abituguru_driver); 16308c2ecf20Sopenharmony_ci} 16318c2ecf20Sopenharmony_ci 16328c2ecf20Sopenharmony_ciMODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); 16338c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Abit uGuru Sensor device"); 16348c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 16358c2ecf20Sopenharmony_ci 16368c2ecf20Sopenharmony_cimodule_init(abituguru_init); 16378c2ecf20Sopenharmony_cimodule_exit(abituguru_exit); 1638