162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * asc7621.c - Part of lm_sensors, Linux kernel modules for hardware monitoring 462306a36Sopenharmony_ci * Copyright (c) 2007, 2010 George Joseph <george.joseph@fairview5.com> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/module.h> 862306a36Sopenharmony_ci#include <linux/init.h> 962306a36Sopenharmony_ci#include <linux/slab.h> 1062306a36Sopenharmony_ci#include <linux/jiffies.h> 1162306a36Sopenharmony_ci#include <linux/i2c.h> 1262306a36Sopenharmony_ci#include <linux/hwmon.h> 1362306a36Sopenharmony_ci#include <linux/hwmon-sysfs.h> 1462306a36Sopenharmony_ci#include <linux/err.h> 1562306a36Sopenharmony_ci#include <linux/mutex.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/* Addresses to scan */ 1862306a36Sopenharmony_cistatic const unsigned short normal_i2c[] = { 1962306a36Sopenharmony_ci 0x2c, 0x2d, 0x2e, I2C_CLIENT_END 2062306a36Sopenharmony_ci}; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cienum asc7621_type { 2362306a36Sopenharmony_ci asc7621, 2462306a36Sopenharmony_ci asc7621a 2562306a36Sopenharmony_ci}; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define INTERVAL_HIGH (HZ + HZ / 2) 2862306a36Sopenharmony_ci#define INTERVAL_LOW (1 * 60 * HZ) 2962306a36Sopenharmony_ci#define PRI_NONE 0 3062306a36Sopenharmony_ci#define PRI_LOW 1 3162306a36Sopenharmony_ci#define PRI_HIGH 2 3262306a36Sopenharmony_ci#define FIRST_CHIP asc7621 3362306a36Sopenharmony_ci#define LAST_CHIP asc7621a 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistruct asc7621_chip { 3662306a36Sopenharmony_ci char *name; 3762306a36Sopenharmony_ci enum asc7621_type chip_type; 3862306a36Sopenharmony_ci u8 company_reg; 3962306a36Sopenharmony_ci u8 company_id; 4062306a36Sopenharmony_ci u8 verstep_reg; 4162306a36Sopenharmony_ci u8 verstep_id; 4262306a36Sopenharmony_ci const unsigned short *addresses; 4362306a36Sopenharmony_ci}; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistatic struct asc7621_chip asc7621_chips[] = { 4662306a36Sopenharmony_ci { 4762306a36Sopenharmony_ci .name = "asc7621", 4862306a36Sopenharmony_ci .chip_type = asc7621, 4962306a36Sopenharmony_ci .company_reg = 0x3e, 5062306a36Sopenharmony_ci .company_id = 0x61, 5162306a36Sopenharmony_ci .verstep_reg = 0x3f, 5262306a36Sopenharmony_ci .verstep_id = 0x6c, 5362306a36Sopenharmony_ci .addresses = normal_i2c, 5462306a36Sopenharmony_ci }, 5562306a36Sopenharmony_ci { 5662306a36Sopenharmony_ci .name = "asc7621a", 5762306a36Sopenharmony_ci .chip_type = asc7621a, 5862306a36Sopenharmony_ci .company_reg = 0x3e, 5962306a36Sopenharmony_ci .company_id = 0x61, 6062306a36Sopenharmony_ci .verstep_reg = 0x3f, 6162306a36Sopenharmony_ci .verstep_id = 0x6d, 6262306a36Sopenharmony_ci .addresses = normal_i2c, 6362306a36Sopenharmony_ci }, 6462306a36Sopenharmony_ci}; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci/* 6762306a36Sopenharmony_ci * Defines the highest register to be used, not the count. 6862306a36Sopenharmony_ci * The actual count will probably be smaller because of gaps 6962306a36Sopenharmony_ci * in the implementation (unused register locations). 7062306a36Sopenharmony_ci * This define will safely set the array size of both the parameter 7162306a36Sopenharmony_ci * and data arrays. 7262306a36Sopenharmony_ci * This comes from the data sheet register description table. 7362306a36Sopenharmony_ci */ 7462306a36Sopenharmony_ci#define LAST_REGISTER 0xff 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistruct asc7621_data { 7762306a36Sopenharmony_ci struct i2c_client client; 7862306a36Sopenharmony_ci struct device *class_dev; 7962306a36Sopenharmony_ci struct mutex update_lock; 8062306a36Sopenharmony_ci bool valid; /* true if following fields are valid */ 8162306a36Sopenharmony_ci unsigned long last_high_reading; /* In jiffies */ 8262306a36Sopenharmony_ci unsigned long last_low_reading; /* In jiffies */ 8362306a36Sopenharmony_ci /* 8462306a36Sopenharmony_ci * Registers we care about occupy the corresponding index 8562306a36Sopenharmony_ci * in the array. Registers we don't care about are left 8662306a36Sopenharmony_ci * at 0. 8762306a36Sopenharmony_ci */ 8862306a36Sopenharmony_ci u8 reg[LAST_REGISTER + 1]; 8962306a36Sopenharmony_ci}; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/* 9262306a36Sopenharmony_ci * Macro to get the parent asc7621_param structure 9362306a36Sopenharmony_ci * from a sensor_device_attribute passed into the 9462306a36Sopenharmony_ci * show/store functions. 9562306a36Sopenharmony_ci */ 9662306a36Sopenharmony_ci#define to_asc7621_param(_sda) \ 9762306a36Sopenharmony_ci container_of(_sda, struct asc7621_param, sda) 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci/* 10062306a36Sopenharmony_ci * Each parameter to be retrieved needs an asc7621_param structure 10162306a36Sopenharmony_ci * allocated. It contains the sensor_device_attribute structure 10262306a36Sopenharmony_ci * and the control info needed to retrieve the value from the register map. 10362306a36Sopenharmony_ci */ 10462306a36Sopenharmony_cistruct asc7621_param { 10562306a36Sopenharmony_ci struct sensor_device_attribute sda; 10662306a36Sopenharmony_ci u8 priority; 10762306a36Sopenharmony_ci u8 msb[3]; 10862306a36Sopenharmony_ci u8 lsb[3]; 10962306a36Sopenharmony_ci u8 mask[3]; 11062306a36Sopenharmony_ci u8 shift[3]; 11162306a36Sopenharmony_ci}; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci/* 11462306a36Sopenharmony_ci * This is the map that ultimately indicates whether we'll be 11562306a36Sopenharmony_ci * retrieving a register value or not, and at what frequency. 11662306a36Sopenharmony_ci */ 11762306a36Sopenharmony_cistatic u8 asc7621_register_priorities[255]; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic struct asc7621_data *asc7621_update_device(struct device *dev); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic inline u8 read_byte(struct i2c_client *client, u8 reg) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci int res = i2c_smbus_read_byte_data(client, reg); 12462306a36Sopenharmony_ci if (res < 0) { 12562306a36Sopenharmony_ci dev_err(&client->dev, 12662306a36Sopenharmony_ci "Unable to read from register 0x%02x.\n", reg); 12762306a36Sopenharmony_ci return 0; 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci return res & 0xff; 13062306a36Sopenharmony_ci} 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic inline int write_byte(struct i2c_client *client, u8 reg, u8 data) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci int res = i2c_smbus_write_byte_data(client, reg, data); 13562306a36Sopenharmony_ci if (res < 0) { 13662306a36Sopenharmony_ci dev_err(&client->dev, 13762306a36Sopenharmony_ci "Unable to write value 0x%02x to register 0x%02x.\n", 13862306a36Sopenharmony_ci data, reg); 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci return res; 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci/* 14462306a36Sopenharmony_ci * Data Handlers 14562306a36Sopenharmony_ci * Each function handles the formatting, storage 14662306a36Sopenharmony_ci * and retrieval of like parameters. 14762306a36Sopenharmony_ci */ 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci#define SETUP_SHOW_DATA_PARAM(d, a) \ 15062306a36Sopenharmony_ci struct sensor_device_attribute *sda = to_sensor_dev_attr(a); \ 15162306a36Sopenharmony_ci struct asc7621_data *data = asc7621_update_device(d); \ 15262306a36Sopenharmony_ci struct asc7621_param *param = to_asc7621_param(sda) 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci#define SETUP_STORE_DATA_PARAM(d, a) \ 15562306a36Sopenharmony_ci struct sensor_device_attribute *sda = to_sensor_dev_attr(a); \ 15662306a36Sopenharmony_ci struct i2c_client *client = to_i2c_client(d); \ 15762306a36Sopenharmony_ci struct asc7621_data *data = i2c_get_clientdata(client); \ 15862306a36Sopenharmony_ci struct asc7621_param *param = to_asc7621_param(sda) 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci/* 16162306a36Sopenharmony_ci * u8 is just what it sounds like...an unsigned byte with no 16262306a36Sopenharmony_ci * special formatting. 16362306a36Sopenharmony_ci */ 16462306a36Sopenharmony_cistatic ssize_t show_u8(struct device *dev, struct device_attribute *attr, 16562306a36Sopenharmony_ci char *buf) 16662306a36Sopenharmony_ci{ 16762306a36Sopenharmony_ci SETUP_SHOW_DATA_PARAM(dev, attr); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci return sprintf(buf, "%u\n", data->reg[param->msb[0]]); 17062306a36Sopenharmony_ci} 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic ssize_t store_u8(struct device *dev, struct device_attribute *attr, 17362306a36Sopenharmony_ci const char *buf, size_t count) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci SETUP_STORE_DATA_PARAM(dev, attr); 17662306a36Sopenharmony_ci long reqval; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci if (kstrtol(buf, 10, &reqval)) 17962306a36Sopenharmony_ci return -EINVAL; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci reqval = clamp_val(reqval, 0, 255); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci mutex_lock(&data->update_lock); 18462306a36Sopenharmony_ci data->reg[param->msb[0]] = reqval; 18562306a36Sopenharmony_ci write_byte(client, param->msb[0], reqval); 18662306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 18762306a36Sopenharmony_ci return count; 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci/* 19162306a36Sopenharmony_ci * Many of the config values occupy only a few bits of a register. 19262306a36Sopenharmony_ci */ 19362306a36Sopenharmony_cistatic ssize_t show_bitmask(struct device *dev, 19462306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci SETUP_SHOW_DATA_PARAM(dev, attr); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci return sprintf(buf, "%u\n", 19962306a36Sopenharmony_ci (data->reg[param->msb[0]] >> param-> 20062306a36Sopenharmony_ci shift[0]) & param->mask[0]); 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic ssize_t store_bitmask(struct device *dev, 20462306a36Sopenharmony_ci struct device_attribute *attr, 20562306a36Sopenharmony_ci const char *buf, size_t count) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci SETUP_STORE_DATA_PARAM(dev, attr); 20862306a36Sopenharmony_ci long reqval; 20962306a36Sopenharmony_ci u8 currval; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci if (kstrtol(buf, 10, &reqval)) 21262306a36Sopenharmony_ci return -EINVAL; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci reqval = clamp_val(reqval, 0, param->mask[0]); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci reqval = (reqval & param->mask[0]) << param->shift[0]; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci mutex_lock(&data->update_lock); 21962306a36Sopenharmony_ci currval = read_byte(client, param->msb[0]); 22062306a36Sopenharmony_ci reqval |= (currval & ~(param->mask[0] << param->shift[0])); 22162306a36Sopenharmony_ci data->reg[param->msb[0]] = reqval; 22262306a36Sopenharmony_ci write_byte(client, param->msb[0], reqval); 22362306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 22462306a36Sopenharmony_ci return count; 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci/* 22862306a36Sopenharmony_ci * 16 bit fan rpm values 22962306a36Sopenharmony_ci * reported by the device as the number of 11.111us periods (90khz) 23062306a36Sopenharmony_ci * between full fan rotations. Therefore... 23162306a36Sopenharmony_ci * RPM = (90000 * 60) / register value 23262306a36Sopenharmony_ci */ 23362306a36Sopenharmony_cistatic ssize_t show_fan16(struct device *dev, 23462306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci SETUP_SHOW_DATA_PARAM(dev, attr); 23762306a36Sopenharmony_ci u16 regval; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci mutex_lock(&data->update_lock); 24062306a36Sopenharmony_ci regval = (data->reg[param->msb[0]] << 8) | data->reg[param->lsb[0]]; 24162306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci return sprintf(buf, "%u\n", 24462306a36Sopenharmony_ci (regval == 0 ? -1 : (regval) == 24562306a36Sopenharmony_ci 0xffff ? 0 : 5400000 / regval)); 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic ssize_t store_fan16(struct device *dev, 24962306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, 25062306a36Sopenharmony_ci size_t count) 25162306a36Sopenharmony_ci{ 25262306a36Sopenharmony_ci SETUP_STORE_DATA_PARAM(dev, attr); 25362306a36Sopenharmony_ci long reqval; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci if (kstrtol(buf, 10, &reqval)) 25662306a36Sopenharmony_ci return -EINVAL; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci /* 25962306a36Sopenharmony_ci * If a minimum RPM of zero is requested, then we set the register to 26062306a36Sopenharmony_ci * 0xffff. This value allows the fan to be stopped completely without 26162306a36Sopenharmony_ci * generating an alarm. 26262306a36Sopenharmony_ci */ 26362306a36Sopenharmony_ci reqval = 26462306a36Sopenharmony_ci (reqval <= 0 ? 0xffff : clamp_val(5400000 / reqval, 0, 0xfffe)); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci mutex_lock(&data->update_lock); 26762306a36Sopenharmony_ci data->reg[param->msb[0]] = (reqval >> 8) & 0xff; 26862306a36Sopenharmony_ci data->reg[param->lsb[0]] = reqval & 0xff; 26962306a36Sopenharmony_ci write_byte(client, param->msb[0], data->reg[param->msb[0]]); 27062306a36Sopenharmony_ci write_byte(client, param->lsb[0], data->reg[param->lsb[0]]); 27162306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci return count; 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci/* 27762306a36Sopenharmony_ci * Voltages are scaled in the device so that the nominal voltage 27862306a36Sopenharmony_ci * is 3/4ths of the 0-255 range (i.e. 192). 27962306a36Sopenharmony_ci * If all voltages are 'normal' then all voltage registers will 28062306a36Sopenharmony_ci * read 0xC0. 28162306a36Sopenharmony_ci * 28262306a36Sopenharmony_ci * The data sheet provides us with the 3/4 scale value for each voltage 28362306a36Sopenharmony_ci * which is stored in in_scaling. The sda->index parameter value provides 28462306a36Sopenharmony_ci * the index into in_scaling. 28562306a36Sopenharmony_ci * 28662306a36Sopenharmony_ci * NOTE: The chip expects the first 2 inputs be 2.5 and 2.25 volts 28762306a36Sopenharmony_ci * respectively. That doesn't mean that's what the motherboard provides. :) 28862306a36Sopenharmony_ci */ 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_cistatic const int asc7621_in_scaling[] = { 29162306a36Sopenharmony_ci 2500, 2250, 3300, 5000, 12000 29262306a36Sopenharmony_ci}; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cistatic ssize_t show_in10(struct device *dev, struct device_attribute *attr, 29562306a36Sopenharmony_ci char *buf) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci SETUP_SHOW_DATA_PARAM(dev, attr); 29862306a36Sopenharmony_ci u16 regval; 29962306a36Sopenharmony_ci u8 nr = sda->index; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci mutex_lock(&data->update_lock); 30262306a36Sopenharmony_ci regval = (data->reg[param->msb[0]] << 8) | (data->reg[param->lsb[0]]); 30362306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci /* The LSB value is a 2-bit scaling of the MSB's LSbit value. */ 30662306a36Sopenharmony_ci regval = (regval >> 6) * asc7621_in_scaling[nr] / (0xc0 << 2); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci return sprintf(buf, "%u\n", regval); 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci/* 8 bit voltage values (the mins and maxs) */ 31262306a36Sopenharmony_cistatic ssize_t show_in8(struct device *dev, struct device_attribute *attr, 31362306a36Sopenharmony_ci char *buf) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci SETUP_SHOW_DATA_PARAM(dev, attr); 31662306a36Sopenharmony_ci u8 nr = sda->index; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci return sprintf(buf, "%u\n", 31962306a36Sopenharmony_ci ((data->reg[param->msb[0]] * 32062306a36Sopenharmony_ci asc7621_in_scaling[nr]) / 0xc0)); 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic ssize_t store_in8(struct device *dev, struct device_attribute *attr, 32462306a36Sopenharmony_ci const char *buf, size_t count) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci SETUP_STORE_DATA_PARAM(dev, attr); 32762306a36Sopenharmony_ci long reqval; 32862306a36Sopenharmony_ci u8 nr = sda->index; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci if (kstrtol(buf, 10, &reqval)) 33162306a36Sopenharmony_ci return -EINVAL; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci reqval = clamp_val(reqval, 0, 0xffff); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci reqval = reqval * 0xc0 / asc7621_in_scaling[nr]; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci reqval = clamp_val(reqval, 0, 0xff); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci mutex_lock(&data->update_lock); 34062306a36Sopenharmony_ci data->reg[param->msb[0]] = reqval; 34162306a36Sopenharmony_ci write_byte(client, param->msb[0], reqval); 34262306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci return count; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic ssize_t show_temp8(struct device *dev, 34862306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci SETUP_SHOW_DATA_PARAM(dev, attr); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci return sprintf(buf, "%d\n", ((s8) data->reg[param->msb[0]]) * 1000); 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistatic ssize_t store_temp8(struct device *dev, 35662306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, 35762306a36Sopenharmony_ci size_t count) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci SETUP_STORE_DATA_PARAM(dev, attr); 36062306a36Sopenharmony_ci long reqval; 36162306a36Sopenharmony_ci s8 temp; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci if (kstrtol(buf, 10, &reqval)) 36462306a36Sopenharmony_ci return -EINVAL; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci reqval = clamp_val(reqval, -127000, 127000); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci temp = reqval / 1000; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci mutex_lock(&data->update_lock); 37162306a36Sopenharmony_ci data->reg[param->msb[0]] = temp; 37262306a36Sopenharmony_ci write_byte(client, param->msb[0], temp); 37362306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 37462306a36Sopenharmony_ci return count; 37562306a36Sopenharmony_ci} 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci/* 37862306a36Sopenharmony_ci * Temperatures that occupy 2 bytes always have the whole 37962306a36Sopenharmony_ci * number of degrees in the MSB with some part of the LSB 38062306a36Sopenharmony_ci * indicating fractional degrees. 38162306a36Sopenharmony_ci */ 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci/* mmmmmmmm.llxxxxxx */ 38462306a36Sopenharmony_cistatic ssize_t show_temp10(struct device *dev, 38562306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci SETUP_SHOW_DATA_PARAM(dev, attr); 38862306a36Sopenharmony_ci u8 msb, lsb; 38962306a36Sopenharmony_ci int temp; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci mutex_lock(&data->update_lock); 39262306a36Sopenharmony_ci msb = data->reg[param->msb[0]]; 39362306a36Sopenharmony_ci lsb = (data->reg[param->lsb[0]] >> 6) & 0x03; 39462306a36Sopenharmony_ci temp = (((s8) msb) * 1000) + (lsb * 250); 39562306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci return sprintf(buf, "%d\n", temp); 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci/* mmmmmm.ll */ 40162306a36Sopenharmony_cistatic ssize_t show_temp62(struct device *dev, 40262306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 40362306a36Sopenharmony_ci{ 40462306a36Sopenharmony_ci SETUP_SHOW_DATA_PARAM(dev, attr); 40562306a36Sopenharmony_ci u8 regval = data->reg[param->msb[0]]; 40662306a36Sopenharmony_ci int temp = ((s8) (regval & 0xfc) * 1000) + ((regval & 0x03) * 250); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci return sprintf(buf, "%d\n", temp); 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_cistatic ssize_t store_temp62(struct device *dev, 41262306a36Sopenharmony_ci struct device_attribute *attr, const char *buf, 41362306a36Sopenharmony_ci size_t count) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci SETUP_STORE_DATA_PARAM(dev, attr); 41662306a36Sopenharmony_ci long reqval, i, f; 41762306a36Sopenharmony_ci s8 temp; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci if (kstrtol(buf, 10, &reqval)) 42062306a36Sopenharmony_ci return -EINVAL; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci reqval = clamp_val(reqval, -32000, 31750); 42362306a36Sopenharmony_ci i = reqval / 1000; 42462306a36Sopenharmony_ci f = reqval - (i * 1000); 42562306a36Sopenharmony_ci temp = i << 2; 42662306a36Sopenharmony_ci temp |= f / 250; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci mutex_lock(&data->update_lock); 42962306a36Sopenharmony_ci data->reg[param->msb[0]] = temp; 43062306a36Sopenharmony_ci write_byte(client, param->msb[0], temp); 43162306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 43262306a36Sopenharmony_ci return count; 43362306a36Sopenharmony_ci} 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci/* 43662306a36Sopenharmony_ci * The aSC7621 doesn't provide an "auto_point2". Instead, you 43762306a36Sopenharmony_ci * specify the auto_point1 and a range. To keep with the sysfs 43862306a36Sopenharmony_ci * hwmon specs, we synthesize the auto_point_2 from them. 43962306a36Sopenharmony_ci */ 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_cistatic const u32 asc7621_range_map[] = { 44262306a36Sopenharmony_ci 2000, 2500, 3330, 4000, 5000, 6670, 8000, 10000, 44362306a36Sopenharmony_ci 13330, 16000, 20000, 26670, 32000, 40000, 53330, 80000, 44462306a36Sopenharmony_ci}; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_cistatic ssize_t show_ap2_temp(struct device *dev, 44762306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 44862306a36Sopenharmony_ci{ 44962306a36Sopenharmony_ci SETUP_SHOW_DATA_PARAM(dev, attr); 45062306a36Sopenharmony_ci long auto_point1; 45162306a36Sopenharmony_ci u8 regval; 45262306a36Sopenharmony_ci int temp; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci mutex_lock(&data->update_lock); 45562306a36Sopenharmony_ci auto_point1 = ((s8) data->reg[param->msb[1]]) * 1000; 45662306a36Sopenharmony_ci regval = 45762306a36Sopenharmony_ci ((data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0]); 45862306a36Sopenharmony_ci temp = auto_point1 + asc7621_range_map[clamp_val(regval, 0, 15)]; 45962306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci return sprintf(buf, "%d\n", temp); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci} 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cistatic ssize_t store_ap2_temp(struct device *dev, 46662306a36Sopenharmony_ci struct device_attribute *attr, 46762306a36Sopenharmony_ci const char *buf, size_t count) 46862306a36Sopenharmony_ci{ 46962306a36Sopenharmony_ci SETUP_STORE_DATA_PARAM(dev, attr); 47062306a36Sopenharmony_ci long reqval, auto_point1; 47162306a36Sopenharmony_ci int i; 47262306a36Sopenharmony_ci u8 currval, newval = 0; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci if (kstrtol(buf, 10, &reqval)) 47562306a36Sopenharmony_ci return -EINVAL; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci mutex_lock(&data->update_lock); 47862306a36Sopenharmony_ci auto_point1 = data->reg[param->msb[1]] * 1000; 47962306a36Sopenharmony_ci reqval = clamp_val(reqval, auto_point1 + 2000, auto_point1 + 80000); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci for (i = ARRAY_SIZE(asc7621_range_map) - 1; i >= 0; i--) { 48262306a36Sopenharmony_ci if (reqval >= auto_point1 + asc7621_range_map[i]) { 48362306a36Sopenharmony_ci newval = i; 48462306a36Sopenharmony_ci break; 48562306a36Sopenharmony_ci } 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci newval = (newval & param->mask[0]) << param->shift[0]; 48962306a36Sopenharmony_ci currval = read_byte(client, param->msb[0]); 49062306a36Sopenharmony_ci newval |= (currval & ~(param->mask[0] << param->shift[0])); 49162306a36Sopenharmony_ci data->reg[param->msb[0]] = newval; 49262306a36Sopenharmony_ci write_byte(client, param->msb[0], newval); 49362306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 49462306a36Sopenharmony_ci return count; 49562306a36Sopenharmony_ci} 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_cistatic ssize_t show_pwm_ac(struct device *dev, 49862306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 49962306a36Sopenharmony_ci{ 50062306a36Sopenharmony_ci SETUP_SHOW_DATA_PARAM(dev, attr); 50162306a36Sopenharmony_ci u8 config, altbit, regval; 50262306a36Sopenharmony_ci static const u8 map[] = { 50362306a36Sopenharmony_ci 0x01, 0x02, 0x04, 0x1f, 0x00, 0x06, 0x07, 0x10, 50462306a36Sopenharmony_ci 0x08, 0x0f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f 50562306a36Sopenharmony_ci }; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci mutex_lock(&data->update_lock); 50862306a36Sopenharmony_ci config = (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0]; 50962306a36Sopenharmony_ci altbit = (data->reg[param->msb[1]] >> param->shift[1]) & param->mask[1]; 51062306a36Sopenharmony_ci regval = config | (altbit << 3); 51162306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci return sprintf(buf, "%u\n", map[clamp_val(regval, 0, 15)]); 51462306a36Sopenharmony_ci} 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_cistatic ssize_t store_pwm_ac(struct device *dev, 51762306a36Sopenharmony_ci struct device_attribute *attr, 51862306a36Sopenharmony_ci const char *buf, size_t count) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci SETUP_STORE_DATA_PARAM(dev, attr); 52162306a36Sopenharmony_ci unsigned long reqval; 52262306a36Sopenharmony_ci u8 currval, config, altbit, newval; 52362306a36Sopenharmony_ci static const u16 map[] = { 52462306a36Sopenharmony_ci 0x04, 0x00, 0x01, 0xff, 0x02, 0xff, 0x05, 0x06, 52562306a36Sopenharmony_ci 0x08, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 52662306a36Sopenharmony_ci 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 52762306a36Sopenharmony_ci 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 52862306a36Sopenharmony_ci }; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci if (kstrtoul(buf, 10, &reqval)) 53162306a36Sopenharmony_ci return -EINVAL; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci if (reqval > 31) 53462306a36Sopenharmony_ci return -EINVAL; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci reqval = map[reqval]; 53762306a36Sopenharmony_ci if (reqval == 0xff) 53862306a36Sopenharmony_ci return -EINVAL; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci config = reqval & 0x07; 54162306a36Sopenharmony_ci altbit = (reqval >> 3) & 0x01; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci config = (config & param->mask[0]) << param->shift[0]; 54462306a36Sopenharmony_ci altbit = (altbit & param->mask[1]) << param->shift[1]; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci mutex_lock(&data->update_lock); 54762306a36Sopenharmony_ci currval = read_byte(client, param->msb[0]); 54862306a36Sopenharmony_ci newval = config | (currval & ~(param->mask[0] << param->shift[0])); 54962306a36Sopenharmony_ci newval = altbit | (newval & ~(param->mask[1] << param->shift[1])); 55062306a36Sopenharmony_ci data->reg[param->msb[0]] = newval; 55162306a36Sopenharmony_ci write_byte(client, param->msb[0], newval); 55262306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 55362306a36Sopenharmony_ci return count; 55462306a36Sopenharmony_ci} 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_cistatic ssize_t show_pwm_enable(struct device *dev, 55762306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 55862306a36Sopenharmony_ci{ 55962306a36Sopenharmony_ci SETUP_SHOW_DATA_PARAM(dev, attr); 56062306a36Sopenharmony_ci u8 config, altbit, minoff, val, newval; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci mutex_lock(&data->update_lock); 56362306a36Sopenharmony_ci config = (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0]; 56462306a36Sopenharmony_ci altbit = (data->reg[param->msb[1]] >> param->shift[1]) & param->mask[1]; 56562306a36Sopenharmony_ci minoff = (data->reg[param->msb[2]] >> param->shift[2]) & param->mask[2]; 56662306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci val = config | (altbit << 3); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci if (val == 3 || val >= 10) 57162306a36Sopenharmony_ci newval = 255; 57262306a36Sopenharmony_ci else if (val == 4) 57362306a36Sopenharmony_ci newval = 0; 57462306a36Sopenharmony_ci else if (val == 7) 57562306a36Sopenharmony_ci newval = 1; 57662306a36Sopenharmony_ci else if (minoff == 1) 57762306a36Sopenharmony_ci newval = 2; 57862306a36Sopenharmony_ci else 57962306a36Sopenharmony_ci newval = 3; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci return sprintf(buf, "%u\n", newval); 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_cistatic ssize_t store_pwm_enable(struct device *dev, 58562306a36Sopenharmony_ci struct device_attribute *attr, 58662306a36Sopenharmony_ci const char *buf, size_t count) 58762306a36Sopenharmony_ci{ 58862306a36Sopenharmony_ci SETUP_STORE_DATA_PARAM(dev, attr); 58962306a36Sopenharmony_ci long reqval; 59062306a36Sopenharmony_ci u8 currval, config, altbit, newval, minoff = 255; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci if (kstrtol(buf, 10, &reqval)) 59362306a36Sopenharmony_ci return -EINVAL; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci switch (reqval) { 59662306a36Sopenharmony_ci case 0: 59762306a36Sopenharmony_ci newval = 0x04; 59862306a36Sopenharmony_ci break; 59962306a36Sopenharmony_ci case 1: 60062306a36Sopenharmony_ci newval = 0x07; 60162306a36Sopenharmony_ci break; 60262306a36Sopenharmony_ci case 2: 60362306a36Sopenharmony_ci newval = 0x00; 60462306a36Sopenharmony_ci minoff = 1; 60562306a36Sopenharmony_ci break; 60662306a36Sopenharmony_ci case 3: 60762306a36Sopenharmony_ci newval = 0x00; 60862306a36Sopenharmony_ci minoff = 0; 60962306a36Sopenharmony_ci break; 61062306a36Sopenharmony_ci case 255: 61162306a36Sopenharmony_ci newval = 0x03; 61262306a36Sopenharmony_ci break; 61362306a36Sopenharmony_ci default: 61462306a36Sopenharmony_ci return -EINVAL; 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci config = newval & 0x07; 61862306a36Sopenharmony_ci altbit = (newval >> 3) & 0x01; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci mutex_lock(&data->update_lock); 62162306a36Sopenharmony_ci config = (config & param->mask[0]) << param->shift[0]; 62262306a36Sopenharmony_ci altbit = (altbit & param->mask[1]) << param->shift[1]; 62362306a36Sopenharmony_ci currval = read_byte(client, param->msb[0]); 62462306a36Sopenharmony_ci newval = config | (currval & ~(param->mask[0] << param->shift[0])); 62562306a36Sopenharmony_ci newval = altbit | (newval & ~(param->mask[1] << param->shift[1])); 62662306a36Sopenharmony_ci data->reg[param->msb[0]] = newval; 62762306a36Sopenharmony_ci write_byte(client, param->msb[0], newval); 62862306a36Sopenharmony_ci if (minoff < 255) { 62962306a36Sopenharmony_ci minoff = (minoff & param->mask[2]) << param->shift[2]; 63062306a36Sopenharmony_ci currval = read_byte(client, param->msb[2]); 63162306a36Sopenharmony_ci newval = 63262306a36Sopenharmony_ci minoff | (currval & ~(param->mask[2] << param->shift[2])); 63362306a36Sopenharmony_ci data->reg[param->msb[2]] = newval; 63462306a36Sopenharmony_ci write_byte(client, param->msb[2], newval); 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 63762306a36Sopenharmony_ci return count; 63862306a36Sopenharmony_ci} 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_cistatic const u32 asc7621_pwm_freq_map[] = { 64162306a36Sopenharmony_ci 10, 15, 23, 30, 38, 47, 62, 94, 64262306a36Sopenharmony_ci 23000, 24000, 25000, 26000, 27000, 28000, 29000, 30000 64362306a36Sopenharmony_ci}; 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_cistatic ssize_t show_pwm_freq(struct device *dev, 64662306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 64762306a36Sopenharmony_ci{ 64862306a36Sopenharmony_ci SETUP_SHOW_DATA_PARAM(dev, attr); 64962306a36Sopenharmony_ci u8 regval = 65062306a36Sopenharmony_ci (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0]; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci regval = clamp_val(regval, 0, 15); 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci return sprintf(buf, "%u\n", asc7621_pwm_freq_map[regval]); 65562306a36Sopenharmony_ci} 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_cistatic ssize_t store_pwm_freq(struct device *dev, 65862306a36Sopenharmony_ci struct device_attribute *attr, 65962306a36Sopenharmony_ci const char *buf, size_t count) 66062306a36Sopenharmony_ci{ 66162306a36Sopenharmony_ci SETUP_STORE_DATA_PARAM(dev, attr); 66262306a36Sopenharmony_ci unsigned long reqval; 66362306a36Sopenharmony_ci u8 currval, newval = 255; 66462306a36Sopenharmony_ci int i; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci if (kstrtoul(buf, 10, &reqval)) 66762306a36Sopenharmony_ci return -EINVAL; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(asc7621_pwm_freq_map); i++) { 67062306a36Sopenharmony_ci if (reqval == asc7621_pwm_freq_map[i]) { 67162306a36Sopenharmony_ci newval = i; 67262306a36Sopenharmony_ci break; 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci if (newval == 255) 67662306a36Sopenharmony_ci return -EINVAL; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci newval = (newval & param->mask[0]) << param->shift[0]; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci mutex_lock(&data->update_lock); 68162306a36Sopenharmony_ci currval = read_byte(client, param->msb[0]); 68262306a36Sopenharmony_ci newval |= (currval & ~(param->mask[0] << param->shift[0])); 68362306a36Sopenharmony_ci data->reg[param->msb[0]] = newval; 68462306a36Sopenharmony_ci write_byte(client, param->msb[0], newval); 68562306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 68662306a36Sopenharmony_ci return count; 68762306a36Sopenharmony_ci} 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_cistatic const u32 asc7621_pwm_auto_spinup_map[] = { 69062306a36Sopenharmony_ci 0, 100, 250, 400, 700, 1000, 2000, 4000 69162306a36Sopenharmony_ci}; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_cistatic ssize_t show_pwm_ast(struct device *dev, 69462306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 69562306a36Sopenharmony_ci{ 69662306a36Sopenharmony_ci SETUP_SHOW_DATA_PARAM(dev, attr); 69762306a36Sopenharmony_ci u8 regval = 69862306a36Sopenharmony_ci (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0]; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci regval = clamp_val(regval, 0, 7); 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci return sprintf(buf, "%u\n", asc7621_pwm_auto_spinup_map[regval]); 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci} 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_cistatic ssize_t store_pwm_ast(struct device *dev, 70762306a36Sopenharmony_ci struct device_attribute *attr, 70862306a36Sopenharmony_ci const char *buf, size_t count) 70962306a36Sopenharmony_ci{ 71062306a36Sopenharmony_ci SETUP_STORE_DATA_PARAM(dev, attr); 71162306a36Sopenharmony_ci long reqval; 71262306a36Sopenharmony_ci u8 currval, newval = 255; 71362306a36Sopenharmony_ci u32 i; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci if (kstrtol(buf, 10, &reqval)) 71662306a36Sopenharmony_ci return -EINVAL; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(asc7621_pwm_auto_spinup_map); i++) { 71962306a36Sopenharmony_ci if (reqval == asc7621_pwm_auto_spinup_map[i]) { 72062306a36Sopenharmony_ci newval = i; 72162306a36Sopenharmony_ci break; 72262306a36Sopenharmony_ci } 72362306a36Sopenharmony_ci } 72462306a36Sopenharmony_ci if (newval == 255) 72562306a36Sopenharmony_ci return -EINVAL; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci newval = (newval & param->mask[0]) << param->shift[0]; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci mutex_lock(&data->update_lock); 73062306a36Sopenharmony_ci currval = read_byte(client, param->msb[0]); 73162306a36Sopenharmony_ci newval |= (currval & ~(param->mask[0] << param->shift[0])); 73262306a36Sopenharmony_ci data->reg[param->msb[0]] = newval; 73362306a36Sopenharmony_ci write_byte(client, param->msb[0], newval); 73462306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 73562306a36Sopenharmony_ci return count; 73662306a36Sopenharmony_ci} 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_cistatic const u32 asc7621_temp_smoothing_time_map[] = { 73962306a36Sopenharmony_ci 35000, 17600, 11800, 7000, 4400, 3000, 1600, 800 74062306a36Sopenharmony_ci}; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_cistatic ssize_t show_temp_st(struct device *dev, 74362306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 74462306a36Sopenharmony_ci{ 74562306a36Sopenharmony_ci SETUP_SHOW_DATA_PARAM(dev, attr); 74662306a36Sopenharmony_ci u8 regval = 74762306a36Sopenharmony_ci (data->reg[param->msb[0]] >> param->shift[0]) & param->mask[0]; 74862306a36Sopenharmony_ci regval = clamp_val(regval, 0, 7); 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci return sprintf(buf, "%u\n", asc7621_temp_smoothing_time_map[regval]); 75162306a36Sopenharmony_ci} 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_cistatic ssize_t store_temp_st(struct device *dev, 75462306a36Sopenharmony_ci struct device_attribute *attr, 75562306a36Sopenharmony_ci const char *buf, size_t count) 75662306a36Sopenharmony_ci{ 75762306a36Sopenharmony_ci SETUP_STORE_DATA_PARAM(dev, attr); 75862306a36Sopenharmony_ci long reqval; 75962306a36Sopenharmony_ci u8 currval, newval = 255; 76062306a36Sopenharmony_ci u32 i; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci if (kstrtol(buf, 10, &reqval)) 76362306a36Sopenharmony_ci return -EINVAL; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(asc7621_temp_smoothing_time_map); i++) { 76662306a36Sopenharmony_ci if (reqval == asc7621_temp_smoothing_time_map[i]) { 76762306a36Sopenharmony_ci newval = i; 76862306a36Sopenharmony_ci break; 76962306a36Sopenharmony_ci } 77062306a36Sopenharmony_ci } 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci if (newval == 255) 77362306a36Sopenharmony_ci return -EINVAL; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci newval = (newval & param->mask[0]) << param->shift[0]; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci mutex_lock(&data->update_lock); 77862306a36Sopenharmony_ci currval = read_byte(client, param->msb[0]); 77962306a36Sopenharmony_ci newval |= (currval & ~(param->mask[0] << param->shift[0])); 78062306a36Sopenharmony_ci data->reg[param->msb[0]] = newval; 78162306a36Sopenharmony_ci write_byte(client, param->msb[0], newval); 78262306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 78362306a36Sopenharmony_ci return count; 78462306a36Sopenharmony_ci} 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci/* 78762306a36Sopenharmony_ci * End of data handlers 78862306a36Sopenharmony_ci * 78962306a36Sopenharmony_ci * These defines do nothing more than make the table easier 79062306a36Sopenharmony_ci * to read when wrapped at column 80. 79162306a36Sopenharmony_ci */ 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci/* 79462306a36Sopenharmony_ci * Creates a variable length array inititalizer. 79562306a36Sopenharmony_ci * VAA(1,3,5,7) would produce {1,3,5,7} 79662306a36Sopenharmony_ci */ 79762306a36Sopenharmony_ci#define VAA(args...) {args} 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci#define PREAD(name, n, pri, rm, rl, m, s, r) \ 80062306a36Sopenharmony_ci {.sda = SENSOR_ATTR(name, S_IRUGO, show_##r, NULL, n), \ 80162306a36Sopenharmony_ci .priority = pri, .msb[0] = rm, .lsb[0] = rl, .mask[0] = m, \ 80262306a36Sopenharmony_ci .shift[0] = s,} 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci#define PWRITE(name, n, pri, rm, rl, m, s, r) \ 80562306a36Sopenharmony_ci {.sda = SENSOR_ATTR(name, S_IRUGO | S_IWUSR, show_##r, store_##r, n), \ 80662306a36Sopenharmony_ci .priority = pri, .msb[0] = rm, .lsb[0] = rl, .mask[0] = m, \ 80762306a36Sopenharmony_ci .shift[0] = s,} 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci/* 81062306a36Sopenharmony_ci * PWRITEM assumes that the initializers for the .msb, .lsb, .mask and .shift 81162306a36Sopenharmony_ci * were created using the VAA macro. 81262306a36Sopenharmony_ci */ 81362306a36Sopenharmony_ci#define PWRITEM(name, n, pri, rm, rl, m, s, r) \ 81462306a36Sopenharmony_ci {.sda = SENSOR_ATTR(name, S_IRUGO | S_IWUSR, show_##r, store_##r, n), \ 81562306a36Sopenharmony_ci .priority = pri, .msb = rm, .lsb = rl, .mask = m, .shift = s,} 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_cistatic struct asc7621_param asc7621_params[] = { 81862306a36Sopenharmony_ci PREAD(in0_input, 0, PRI_HIGH, 0x20, 0x13, 0, 0, in10), 81962306a36Sopenharmony_ci PREAD(in1_input, 1, PRI_HIGH, 0x21, 0x18, 0, 0, in10), 82062306a36Sopenharmony_ci PREAD(in2_input, 2, PRI_HIGH, 0x22, 0x11, 0, 0, in10), 82162306a36Sopenharmony_ci PREAD(in3_input, 3, PRI_HIGH, 0x23, 0x12, 0, 0, in10), 82262306a36Sopenharmony_ci PREAD(in4_input, 4, PRI_HIGH, 0x24, 0x14, 0, 0, in10), 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci PWRITE(in0_min, 0, PRI_LOW, 0x44, 0, 0, 0, in8), 82562306a36Sopenharmony_ci PWRITE(in1_min, 1, PRI_LOW, 0x46, 0, 0, 0, in8), 82662306a36Sopenharmony_ci PWRITE(in2_min, 2, PRI_LOW, 0x48, 0, 0, 0, in8), 82762306a36Sopenharmony_ci PWRITE(in3_min, 3, PRI_LOW, 0x4a, 0, 0, 0, in8), 82862306a36Sopenharmony_ci PWRITE(in4_min, 4, PRI_LOW, 0x4c, 0, 0, 0, in8), 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci PWRITE(in0_max, 0, PRI_LOW, 0x45, 0, 0, 0, in8), 83162306a36Sopenharmony_ci PWRITE(in1_max, 1, PRI_LOW, 0x47, 0, 0, 0, in8), 83262306a36Sopenharmony_ci PWRITE(in2_max, 2, PRI_LOW, 0x49, 0, 0, 0, in8), 83362306a36Sopenharmony_ci PWRITE(in3_max, 3, PRI_LOW, 0x4b, 0, 0, 0, in8), 83462306a36Sopenharmony_ci PWRITE(in4_max, 4, PRI_LOW, 0x4d, 0, 0, 0, in8), 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci PREAD(in0_alarm, 0, PRI_HIGH, 0x41, 0, 0x01, 0, bitmask), 83762306a36Sopenharmony_ci PREAD(in1_alarm, 1, PRI_HIGH, 0x41, 0, 0x01, 1, bitmask), 83862306a36Sopenharmony_ci PREAD(in2_alarm, 2, PRI_HIGH, 0x41, 0, 0x01, 2, bitmask), 83962306a36Sopenharmony_ci PREAD(in3_alarm, 3, PRI_HIGH, 0x41, 0, 0x01, 3, bitmask), 84062306a36Sopenharmony_ci PREAD(in4_alarm, 4, PRI_HIGH, 0x42, 0, 0x01, 0, bitmask), 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci PREAD(fan1_input, 0, PRI_HIGH, 0x29, 0x28, 0, 0, fan16), 84362306a36Sopenharmony_ci PREAD(fan2_input, 1, PRI_HIGH, 0x2b, 0x2a, 0, 0, fan16), 84462306a36Sopenharmony_ci PREAD(fan3_input, 2, PRI_HIGH, 0x2d, 0x2c, 0, 0, fan16), 84562306a36Sopenharmony_ci PREAD(fan4_input, 3, PRI_HIGH, 0x2f, 0x2e, 0, 0, fan16), 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci PWRITE(fan1_min, 0, PRI_LOW, 0x55, 0x54, 0, 0, fan16), 84862306a36Sopenharmony_ci PWRITE(fan2_min, 1, PRI_LOW, 0x57, 0x56, 0, 0, fan16), 84962306a36Sopenharmony_ci PWRITE(fan3_min, 2, PRI_LOW, 0x59, 0x58, 0, 0, fan16), 85062306a36Sopenharmony_ci PWRITE(fan4_min, 3, PRI_LOW, 0x5b, 0x5a, 0, 0, fan16), 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci PREAD(fan1_alarm, 0, PRI_HIGH, 0x42, 0, 0x01, 2, bitmask), 85362306a36Sopenharmony_ci PREAD(fan2_alarm, 1, PRI_HIGH, 0x42, 0, 0x01, 3, bitmask), 85462306a36Sopenharmony_ci PREAD(fan3_alarm, 2, PRI_HIGH, 0x42, 0, 0x01, 4, bitmask), 85562306a36Sopenharmony_ci PREAD(fan4_alarm, 3, PRI_HIGH, 0x42, 0, 0x01, 5, bitmask), 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci PREAD(temp1_input, 0, PRI_HIGH, 0x25, 0x10, 0, 0, temp10), 85862306a36Sopenharmony_ci PREAD(temp2_input, 1, PRI_HIGH, 0x26, 0x15, 0, 0, temp10), 85962306a36Sopenharmony_ci PREAD(temp3_input, 2, PRI_HIGH, 0x27, 0x16, 0, 0, temp10), 86062306a36Sopenharmony_ci PREAD(temp4_input, 3, PRI_HIGH, 0x33, 0x17, 0, 0, temp10), 86162306a36Sopenharmony_ci PREAD(temp5_input, 4, PRI_HIGH, 0xf7, 0xf6, 0, 0, temp10), 86262306a36Sopenharmony_ci PREAD(temp6_input, 5, PRI_HIGH, 0xf9, 0xf8, 0, 0, temp10), 86362306a36Sopenharmony_ci PREAD(temp7_input, 6, PRI_HIGH, 0xfb, 0xfa, 0, 0, temp10), 86462306a36Sopenharmony_ci PREAD(temp8_input, 7, PRI_HIGH, 0xfd, 0xfc, 0, 0, temp10), 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci PWRITE(temp1_min, 0, PRI_LOW, 0x4e, 0, 0, 0, temp8), 86762306a36Sopenharmony_ci PWRITE(temp2_min, 1, PRI_LOW, 0x50, 0, 0, 0, temp8), 86862306a36Sopenharmony_ci PWRITE(temp3_min, 2, PRI_LOW, 0x52, 0, 0, 0, temp8), 86962306a36Sopenharmony_ci PWRITE(temp4_min, 3, PRI_LOW, 0x34, 0, 0, 0, temp8), 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci PWRITE(temp1_max, 0, PRI_LOW, 0x4f, 0, 0, 0, temp8), 87262306a36Sopenharmony_ci PWRITE(temp2_max, 1, PRI_LOW, 0x51, 0, 0, 0, temp8), 87362306a36Sopenharmony_ci PWRITE(temp3_max, 2, PRI_LOW, 0x53, 0, 0, 0, temp8), 87462306a36Sopenharmony_ci PWRITE(temp4_max, 3, PRI_LOW, 0x35, 0, 0, 0, temp8), 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci PREAD(temp1_alarm, 0, PRI_HIGH, 0x41, 0, 0x01, 4, bitmask), 87762306a36Sopenharmony_ci PREAD(temp2_alarm, 1, PRI_HIGH, 0x41, 0, 0x01, 5, bitmask), 87862306a36Sopenharmony_ci PREAD(temp3_alarm, 2, PRI_HIGH, 0x41, 0, 0x01, 6, bitmask), 87962306a36Sopenharmony_ci PREAD(temp4_alarm, 3, PRI_HIGH, 0x43, 0, 0x01, 0, bitmask), 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci PWRITE(temp1_source, 0, PRI_LOW, 0x02, 0, 0x07, 4, bitmask), 88262306a36Sopenharmony_ci PWRITE(temp2_source, 1, PRI_LOW, 0x02, 0, 0x07, 0, bitmask), 88362306a36Sopenharmony_ci PWRITE(temp3_source, 2, PRI_LOW, 0x03, 0, 0x07, 4, bitmask), 88462306a36Sopenharmony_ci PWRITE(temp4_source, 3, PRI_LOW, 0x03, 0, 0x07, 0, bitmask), 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci PWRITE(temp1_smoothing_enable, 0, PRI_LOW, 0x62, 0, 0x01, 3, bitmask), 88762306a36Sopenharmony_ci PWRITE(temp2_smoothing_enable, 1, PRI_LOW, 0x63, 0, 0x01, 7, bitmask), 88862306a36Sopenharmony_ci PWRITE(temp3_smoothing_enable, 2, PRI_LOW, 0x63, 0, 0x01, 3, bitmask), 88962306a36Sopenharmony_ci PWRITE(temp4_smoothing_enable, 3, PRI_LOW, 0x3c, 0, 0x01, 3, bitmask), 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci PWRITE(temp1_smoothing_time, 0, PRI_LOW, 0x62, 0, 0x07, 0, temp_st), 89262306a36Sopenharmony_ci PWRITE(temp2_smoothing_time, 1, PRI_LOW, 0x63, 0, 0x07, 4, temp_st), 89362306a36Sopenharmony_ci PWRITE(temp3_smoothing_time, 2, PRI_LOW, 0x63, 0, 0x07, 0, temp_st), 89462306a36Sopenharmony_ci PWRITE(temp4_smoothing_time, 3, PRI_LOW, 0x3c, 0, 0x07, 0, temp_st), 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci PWRITE(temp1_auto_point1_temp_hyst, 0, PRI_LOW, 0x6d, 0, 0x0f, 4, 89762306a36Sopenharmony_ci bitmask), 89862306a36Sopenharmony_ci PWRITE(temp2_auto_point1_temp_hyst, 1, PRI_LOW, 0x6d, 0, 0x0f, 0, 89962306a36Sopenharmony_ci bitmask), 90062306a36Sopenharmony_ci PWRITE(temp3_auto_point1_temp_hyst, 2, PRI_LOW, 0x6e, 0, 0x0f, 4, 90162306a36Sopenharmony_ci bitmask), 90262306a36Sopenharmony_ci PWRITE(temp4_auto_point1_temp_hyst, 3, PRI_LOW, 0x6e, 0, 0x0f, 0, 90362306a36Sopenharmony_ci bitmask), 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci PREAD(temp1_auto_point2_temp_hyst, 0, PRI_LOW, 0x6d, 0, 0x0f, 4, 90662306a36Sopenharmony_ci bitmask), 90762306a36Sopenharmony_ci PREAD(temp2_auto_point2_temp_hyst, 1, PRI_LOW, 0x6d, 0, 0x0f, 0, 90862306a36Sopenharmony_ci bitmask), 90962306a36Sopenharmony_ci PREAD(temp3_auto_point2_temp_hyst, 2, PRI_LOW, 0x6e, 0, 0x0f, 4, 91062306a36Sopenharmony_ci bitmask), 91162306a36Sopenharmony_ci PREAD(temp4_auto_point2_temp_hyst, 3, PRI_LOW, 0x6e, 0, 0x0f, 0, 91262306a36Sopenharmony_ci bitmask), 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci PWRITE(temp1_auto_point1_temp, 0, PRI_LOW, 0x67, 0, 0, 0, temp8), 91562306a36Sopenharmony_ci PWRITE(temp2_auto_point1_temp, 1, PRI_LOW, 0x68, 0, 0, 0, temp8), 91662306a36Sopenharmony_ci PWRITE(temp3_auto_point1_temp, 2, PRI_LOW, 0x69, 0, 0, 0, temp8), 91762306a36Sopenharmony_ci PWRITE(temp4_auto_point1_temp, 3, PRI_LOW, 0x3b, 0, 0, 0, temp8), 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci PWRITEM(temp1_auto_point2_temp, 0, PRI_LOW, VAA(0x5f, 0x67), VAA(0), 92062306a36Sopenharmony_ci VAA(0x0f), VAA(4), ap2_temp), 92162306a36Sopenharmony_ci PWRITEM(temp2_auto_point2_temp, 1, PRI_LOW, VAA(0x60, 0x68), VAA(0), 92262306a36Sopenharmony_ci VAA(0x0f), VAA(4), ap2_temp), 92362306a36Sopenharmony_ci PWRITEM(temp3_auto_point2_temp, 2, PRI_LOW, VAA(0x61, 0x69), VAA(0), 92462306a36Sopenharmony_ci VAA(0x0f), VAA(4), ap2_temp), 92562306a36Sopenharmony_ci PWRITEM(temp4_auto_point2_temp, 3, PRI_LOW, VAA(0x3c, 0x3b), VAA(0), 92662306a36Sopenharmony_ci VAA(0x0f), VAA(4), ap2_temp), 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci PWRITE(temp1_crit, 0, PRI_LOW, 0x6a, 0, 0, 0, temp8), 92962306a36Sopenharmony_ci PWRITE(temp2_crit, 1, PRI_LOW, 0x6b, 0, 0, 0, temp8), 93062306a36Sopenharmony_ci PWRITE(temp3_crit, 2, PRI_LOW, 0x6c, 0, 0, 0, temp8), 93162306a36Sopenharmony_ci PWRITE(temp4_crit, 3, PRI_LOW, 0x3d, 0, 0, 0, temp8), 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci PWRITE(temp5_enable, 4, PRI_LOW, 0x0e, 0, 0x01, 0, bitmask), 93462306a36Sopenharmony_ci PWRITE(temp6_enable, 5, PRI_LOW, 0x0e, 0, 0x01, 1, bitmask), 93562306a36Sopenharmony_ci PWRITE(temp7_enable, 6, PRI_LOW, 0x0e, 0, 0x01, 2, bitmask), 93662306a36Sopenharmony_ci PWRITE(temp8_enable, 7, PRI_LOW, 0x0e, 0, 0x01, 3, bitmask), 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci PWRITE(remote1_offset, 0, PRI_LOW, 0x1c, 0, 0, 0, temp62), 93962306a36Sopenharmony_ci PWRITE(remote2_offset, 1, PRI_LOW, 0x1d, 0, 0, 0, temp62), 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci PWRITE(pwm1, 0, PRI_HIGH, 0x30, 0, 0, 0, u8), 94262306a36Sopenharmony_ci PWRITE(pwm2, 1, PRI_HIGH, 0x31, 0, 0, 0, u8), 94362306a36Sopenharmony_ci PWRITE(pwm3, 2, PRI_HIGH, 0x32, 0, 0, 0, u8), 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci PWRITE(pwm1_invert, 0, PRI_LOW, 0x5c, 0, 0x01, 4, bitmask), 94662306a36Sopenharmony_ci PWRITE(pwm2_invert, 1, PRI_LOW, 0x5d, 0, 0x01, 4, bitmask), 94762306a36Sopenharmony_ci PWRITE(pwm3_invert, 2, PRI_LOW, 0x5e, 0, 0x01, 4, bitmask), 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci PWRITEM(pwm1_enable, 0, PRI_LOW, VAA(0x5c, 0x5c, 0x62), VAA(0, 0, 0), 95062306a36Sopenharmony_ci VAA(0x07, 0x01, 0x01), VAA(5, 3, 5), pwm_enable), 95162306a36Sopenharmony_ci PWRITEM(pwm2_enable, 1, PRI_LOW, VAA(0x5d, 0x5d, 0x62), VAA(0, 0, 0), 95262306a36Sopenharmony_ci VAA(0x07, 0x01, 0x01), VAA(5, 3, 6), pwm_enable), 95362306a36Sopenharmony_ci PWRITEM(pwm3_enable, 2, PRI_LOW, VAA(0x5e, 0x5e, 0x62), VAA(0, 0, 0), 95462306a36Sopenharmony_ci VAA(0x07, 0x01, 0x01), VAA(5, 3, 7), pwm_enable), 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci PWRITEM(pwm1_auto_channels, 0, PRI_LOW, VAA(0x5c, 0x5c), VAA(0, 0), 95762306a36Sopenharmony_ci VAA(0x07, 0x01), VAA(5, 3), pwm_ac), 95862306a36Sopenharmony_ci PWRITEM(pwm2_auto_channels, 1, PRI_LOW, VAA(0x5d, 0x5d), VAA(0, 0), 95962306a36Sopenharmony_ci VAA(0x07, 0x01), VAA(5, 3), pwm_ac), 96062306a36Sopenharmony_ci PWRITEM(pwm3_auto_channels, 2, PRI_LOW, VAA(0x5e, 0x5e), VAA(0, 0), 96162306a36Sopenharmony_ci VAA(0x07, 0x01), VAA(5, 3), pwm_ac), 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci PWRITE(pwm1_auto_point1_pwm, 0, PRI_LOW, 0x64, 0, 0, 0, u8), 96462306a36Sopenharmony_ci PWRITE(pwm2_auto_point1_pwm, 1, PRI_LOW, 0x65, 0, 0, 0, u8), 96562306a36Sopenharmony_ci PWRITE(pwm3_auto_point1_pwm, 2, PRI_LOW, 0x66, 0, 0, 0, u8), 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci PWRITE(pwm1_auto_point2_pwm, 0, PRI_LOW, 0x38, 0, 0, 0, u8), 96862306a36Sopenharmony_ci PWRITE(pwm2_auto_point2_pwm, 1, PRI_LOW, 0x39, 0, 0, 0, u8), 96962306a36Sopenharmony_ci PWRITE(pwm3_auto_point2_pwm, 2, PRI_LOW, 0x3a, 0, 0, 0, u8), 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci PWRITE(pwm1_freq, 0, PRI_LOW, 0x5f, 0, 0x0f, 0, pwm_freq), 97262306a36Sopenharmony_ci PWRITE(pwm2_freq, 1, PRI_LOW, 0x60, 0, 0x0f, 0, pwm_freq), 97362306a36Sopenharmony_ci PWRITE(pwm3_freq, 2, PRI_LOW, 0x61, 0, 0x0f, 0, pwm_freq), 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci PREAD(pwm1_auto_zone_assigned, 0, PRI_LOW, 0, 0, 0x03, 2, bitmask), 97662306a36Sopenharmony_ci PREAD(pwm2_auto_zone_assigned, 1, PRI_LOW, 0, 0, 0x03, 4, bitmask), 97762306a36Sopenharmony_ci PREAD(pwm3_auto_zone_assigned, 2, PRI_LOW, 0, 0, 0x03, 6, bitmask), 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_ci PWRITE(pwm1_auto_spinup_time, 0, PRI_LOW, 0x5c, 0, 0x07, 0, pwm_ast), 98062306a36Sopenharmony_ci PWRITE(pwm2_auto_spinup_time, 1, PRI_LOW, 0x5d, 0, 0x07, 0, pwm_ast), 98162306a36Sopenharmony_ci PWRITE(pwm3_auto_spinup_time, 2, PRI_LOW, 0x5e, 0, 0x07, 0, pwm_ast), 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci PWRITE(peci_enable, 0, PRI_LOW, 0x40, 0, 0x01, 4, bitmask), 98462306a36Sopenharmony_ci PWRITE(peci_avg, 0, PRI_LOW, 0x36, 0, 0x07, 0, bitmask), 98562306a36Sopenharmony_ci PWRITE(peci_domain, 0, PRI_LOW, 0x36, 0, 0x01, 3, bitmask), 98662306a36Sopenharmony_ci PWRITE(peci_legacy, 0, PRI_LOW, 0x36, 0, 0x01, 4, bitmask), 98762306a36Sopenharmony_ci PWRITE(peci_diode, 0, PRI_LOW, 0x0e, 0, 0x07, 4, bitmask), 98862306a36Sopenharmony_ci PWRITE(peci_4domain, 0, PRI_LOW, 0x0e, 0, 0x01, 4, bitmask), 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci}; 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_cistatic struct asc7621_data *asc7621_update_device(struct device *dev) 99362306a36Sopenharmony_ci{ 99462306a36Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 99562306a36Sopenharmony_ci struct asc7621_data *data = i2c_get_clientdata(client); 99662306a36Sopenharmony_ci int i; 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci/* 99962306a36Sopenharmony_ci * The asc7621 chips guarantee consistent reads of multi-byte values 100062306a36Sopenharmony_ci * regardless of the order of the reads. No special logic is needed 100162306a36Sopenharmony_ci * so we can just read the registers in whatever order they appear 100262306a36Sopenharmony_ci * in the asc7621_params array. 100362306a36Sopenharmony_ci */ 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci mutex_lock(&data->update_lock); 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci /* Read all the high priority registers */ 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci if (!data->valid || 101062306a36Sopenharmony_ci time_after(jiffies, data->last_high_reading + INTERVAL_HIGH)) { 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(asc7621_register_priorities); i++) { 101362306a36Sopenharmony_ci if (asc7621_register_priorities[i] == PRI_HIGH) { 101462306a36Sopenharmony_ci data->reg[i] = 101562306a36Sopenharmony_ci i2c_smbus_read_byte_data(client, i) & 0xff; 101662306a36Sopenharmony_ci } 101762306a36Sopenharmony_ci } 101862306a36Sopenharmony_ci data->last_high_reading = jiffies; 101962306a36Sopenharmony_ci } /* last_reading */ 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci /* Read all the low priority registers. */ 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci if (!data->valid || 102462306a36Sopenharmony_ci time_after(jiffies, data->last_low_reading + INTERVAL_LOW)) { 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(asc7621_params); i++) { 102762306a36Sopenharmony_ci if (asc7621_register_priorities[i] == PRI_LOW) { 102862306a36Sopenharmony_ci data->reg[i] = 102962306a36Sopenharmony_ci i2c_smbus_read_byte_data(client, i) & 0xff; 103062306a36Sopenharmony_ci } 103162306a36Sopenharmony_ci } 103262306a36Sopenharmony_ci data->last_low_reading = jiffies; 103362306a36Sopenharmony_ci } /* last_reading */ 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci data->valid = true; 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci mutex_unlock(&data->update_lock); 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci return data; 104062306a36Sopenharmony_ci} 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci/* 104362306a36Sopenharmony_ci * Standard detection and initialization below 104462306a36Sopenharmony_ci * 104562306a36Sopenharmony_ci * Helper function that checks if an address is valid 104662306a36Sopenharmony_ci * for a particular chip. 104762306a36Sopenharmony_ci */ 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_cistatic inline int valid_address_for_chip(int chip_type, int address) 105062306a36Sopenharmony_ci{ 105162306a36Sopenharmony_ci int i; 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci for (i = 0; asc7621_chips[chip_type].addresses[i] != I2C_CLIENT_END; 105462306a36Sopenharmony_ci i++) { 105562306a36Sopenharmony_ci if (asc7621_chips[chip_type].addresses[i] == address) 105662306a36Sopenharmony_ci return 1; 105762306a36Sopenharmony_ci } 105862306a36Sopenharmony_ci return 0; 105962306a36Sopenharmony_ci} 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_cistatic void asc7621_init_client(struct i2c_client *client) 106262306a36Sopenharmony_ci{ 106362306a36Sopenharmony_ci int value; 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci /* Warn if part was not "READY" */ 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci value = read_byte(client, 0x40); 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci if (value & 0x02) { 107062306a36Sopenharmony_ci dev_err(&client->dev, 107162306a36Sopenharmony_ci "Client (%d,0x%02x) config is locked.\n", 107262306a36Sopenharmony_ci i2c_adapter_id(client->adapter), client->addr); 107362306a36Sopenharmony_ci } 107462306a36Sopenharmony_ci if (!(value & 0x04)) { 107562306a36Sopenharmony_ci dev_err(&client->dev, "Client (%d,0x%02x) is not ready.\n", 107662306a36Sopenharmony_ci i2c_adapter_id(client->adapter), client->addr); 107762306a36Sopenharmony_ci } 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci/* 108062306a36Sopenharmony_ci * Start monitoring 108162306a36Sopenharmony_ci * 108262306a36Sopenharmony_ci * Try to clear LOCK, Set START, save everything else 108362306a36Sopenharmony_ci */ 108462306a36Sopenharmony_ci value = (value & ~0x02) | 0x01; 108562306a36Sopenharmony_ci write_byte(client, 0x40, value & 0xff); 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci} 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_cistatic int 109062306a36Sopenharmony_ciasc7621_probe(struct i2c_client *client) 109162306a36Sopenharmony_ci{ 109262306a36Sopenharmony_ci struct asc7621_data *data; 109362306a36Sopenharmony_ci int i, err; 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 109662306a36Sopenharmony_ci return -EIO; 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci data = devm_kzalloc(&client->dev, sizeof(struct asc7621_data), 109962306a36Sopenharmony_ci GFP_KERNEL); 110062306a36Sopenharmony_ci if (data == NULL) 110162306a36Sopenharmony_ci return -ENOMEM; 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci i2c_set_clientdata(client, data); 110462306a36Sopenharmony_ci mutex_init(&data->update_lock); 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci /* Initialize the asc7621 chip */ 110762306a36Sopenharmony_ci asc7621_init_client(client); 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci /* Create the sysfs entries */ 111062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(asc7621_params); i++) { 111162306a36Sopenharmony_ci err = 111262306a36Sopenharmony_ci device_create_file(&client->dev, 111362306a36Sopenharmony_ci &(asc7621_params[i].sda.dev_attr)); 111462306a36Sopenharmony_ci if (err) 111562306a36Sopenharmony_ci goto exit_remove; 111662306a36Sopenharmony_ci } 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci data->class_dev = hwmon_device_register(&client->dev); 111962306a36Sopenharmony_ci if (IS_ERR(data->class_dev)) { 112062306a36Sopenharmony_ci err = PTR_ERR(data->class_dev); 112162306a36Sopenharmony_ci goto exit_remove; 112262306a36Sopenharmony_ci } 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci return 0; 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ciexit_remove: 112762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(asc7621_params); i++) { 112862306a36Sopenharmony_ci device_remove_file(&client->dev, 112962306a36Sopenharmony_ci &(asc7621_params[i].sda.dev_attr)); 113062306a36Sopenharmony_ci } 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci return err; 113362306a36Sopenharmony_ci} 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_cistatic int asc7621_detect(struct i2c_client *client, 113662306a36Sopenharmony_ci struct i2c_board_info *info) 113762306a36Sopenharmony_ci{ 113862306a36Sopenharmony_ci struct i2c_adapter *adapter = client->adapter; 113962306a36Sopenharmony_ci int company, verstep, chip_index; 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 114262306a36Sopenharmony_ci return -ENODEV; 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci for (chip_index = FIRST_CHIP; chip_index <= LAST_CHIP; chip_index++) { 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci if (!valid_address_for_chip(chip_index, client->addr)) 114762306a36Sopenharmony_ci continue; 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci company = read_byte(client, 115062306a36Sopenharmony_ci asc7621_chips[chip_index].company_reg); 115162306a36Sopenharmony_ci verstep = read_byte(client, 115262306a36Sopenharmony_ci asc7621_chips[chip_index].verstep_reg); 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci if (company == asc7621_chips[chip_index].company_id && 115562306a36Sopenharmony_ci verstep == asc7621_chips[chip_index].verstep_id) { 115662306a36Sopenharmony_ci strscpy(info->type, asc7621_chips[chip_index].name, 115762306a36Sopenharmony_ci I2C_NAME_SIZE); 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci dev_info(&adapter->dev, "Matched %s at 0x%02x\n", 116062306a36Sopenharmony_ci asc7621_chips[chip_index].name, client->addr); 116162306a36Sopenharmony_ci return 0; 116262306a36Sopenharmony_ci } 116362306a36Sopenharmony_ci } 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci return -ENODEV; 116662306a36Sopenharmony_ci} 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_cistatic void asc7621_remove(struct i2c_client *client) 116962306a36Sopenharmony_ci{ 117062306a36Sopenharmony_ci struct asc7621_data *data = i2c_get_clientdata(client); 117162306a36Sopenharmony_ci int i; 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci hwmon_device_unregister(data->class_dev); 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(asc7621_params); i++) { 117662306a36Sopenharmony_ci device_remove_file(&client->dev, 117762306a36Sopenharmony_ci &(asc7621_params[i].sda.dev_attr)); 117862306a36Sopenharmony_ci } 117962306a36Sopenharmony_ci} 118062306a36Sopenharmony_ci 118162306a36Sopenharmony_cistatic const struct i2c_device_id asc7621_id[] = { 118262306a36Sopenharmony_ci {"asc7621", asc7621}, 118362306a36Sopenharmony_ci {"asc7621a", asc7621a}, 118462306a36Sopenharmony_ci {}, 118562306a36Sopenharmony_ci}; 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, asc7621_id); 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_cistatic struct i2c_driver asc7621_driver = { 119062306a36Sopenharmony_ci .class = I2C_CLASS_HWMON, 119162306a36Sopenharmony_ci .driver = { 119262306a36Sopenharmony_ci .name = "asc7621", 119362306a36Sopenharmony_ci }, 119462306a36Sopenharmony_ci .probe = asc7621_probe, 119562306a36Sopenharmony_ci .remove = asc7621_remove, 119662306a36Sopenharmony_ci .id_table = asc7621_id, 119762306a36Sopenharmony_ci .detect = asc7621_detect, 119862306a36Sopenharmony_ci .address_list = normal_i2c, 119962306a36Sopenharmony_ci}; 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_cistatic int __init sm_asc7621_init(void) 120262306a36Sopenharmony_ci{ 120362306a36Sopenharmony_ci int i, j; 120462306a36Sopenharmony_ci/* 120562306a36Sopenharmony_ci * Collect all the registers needed into a single array. 120662306a36Sopenharmony_ci * This way, if a register isn't actually used for anything, 120762306a36Sopenharmony_ci * we don't retrieve it. 120862306a36Sopenharmony_ci */ 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(asc7621_params); i++) { 121162306a36Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(asc7621_params[i].msb); j++) 121262306a36Sopenharmony_ci asc7621_register_priorities[asc7621_params[i].msb[j]] = 121362306a36Sopenharmony_ci asc7621_params[i].priority; 121462306a36Sopenharmony_ci for (j = 0; j < ARRAY_SIZE(asc7621_params[i].lsb); j++) 121562306a36Sopenharmony_ci asc7621_register_priorities[asc7621_params[i].lsb[j]] = 121662306a36Sopenharmony_ci asc7621_params[i].priority; 121762306a36Sopenharmony_ci } 121862306a36Sopenharmony_ci return i2c_add_driver(&asc7621_driver); 121962306a36Sopenharmony_ci} 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_cistatic void __exit sm_asc7621_exit(void) 122262306a36Sopenharmony_ci{ 122362306a36Sopenharmony_ci i2c_del_driver(&asc7621_driver); 122462306a36Sopenharmony_ci} 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 122762306a36Sopenharmony_ciMODULE_AUTHOR("George Joseph"); 122862306a36Sopenharmony_ciMODULE_DESCRIPTION("Andigilog aSC7621 and aSC7621a driver"); 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_cimodule_init(sm_asc7621_init); 123162306a36Sopenharmony_cimodule_exit(sm_asc7621_exit); 1232