mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-28 16:56:26 +00:00
hwmon: (lm75) Add AMS AS6200 temperature sensor
as6200 is a temperature sensor with 0.0625°C resolution and a range between -40°C to 125°C. By default, the driver configures as6200 as following: - Converstion rate: 8 Hz - Conversion mode: continuous - Consecutive fault counts: 4 samples - Alert state: high polarity - Alert mode: comparator mode Interrupt is supported for the alert pin. Signed-off-by: Abdel Alkuor <alkuor@gmail.com> Link: https://lore.kernel.org/r/d1686678991bf8ee0d00cb08ca046798f37ca4b3.1703127334.git.alkuor@gmail.com Signed-off-by: Guenter Roeck <linux@roeck-us.net>
This commit is contained in:
parent
de9c6033fb
commit
4b6358e1fe
@ -133,6 +133,16 @@ Supported chips:
|
||||
|
||||
https://www.nxp.com/docs/en/data-sheet/PCT2075.pdf
|
||||
|
||||
* AMS OSRAM AS6200
|
||||
|
||||
Prefix: 'as6200'
|
||||
|
||||
Addresses scanned: none
|
||||
|
||||
Datasheet: Publicly available at the AMS website
|
||||
|
||||
https://ams.com/documents/20143/36005/AS6200_DS000449_4-00.pdf
|
||||
|
||||
Author: Frodo Looijaard <frodol@dds.nl>
|
||||
|
||||
Description
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/i2c.h>
|
||||
@ -24,6 +25,7 @@
|
||||
|
||||
enum lm75_type { /* keep sorted in alphabetical order */
|
||||
adt75,
|
||||
as6200,
|
||||
at30ts74,
|
||||
ds1775,
|
||||
ds75,
|
||||
@ -54,6 +56,7 @@ enum lm75_type { /* keep sorted in alphabetical order */
|
||||
|
||||
/**
|
||||
* struct lm75_params - lm75 configuration parameters.
|
||||
* @config_reg_16bits: Configure register size is 2 bytes.
|
||||
* @set_mask: Bits to set in configuration register when configuring
|
||||
* the chip.
|
||||
* @clr_mask: Bits to clear in configuration register when configuring
|
||||
@ -74,17 +77,20 @@ enum lm75_type { /* keep sorted in alphabetical order */
|
||||
* @sample_times: All the possible sample times to be set. Mandatory if
|
||||
* num_sample_times is larger than 1. If set, number of
|
||||
* entries must match num_sample_times.
|
||||
* @alarm: Alarm bit is supported.
|
||||
*/
|
||||
|
||||
struct lm75_params {
|
||||
u8 set_mask;
|
||||
u8 clr_mask;
|
||||
bool config_reg_16bits;
|
||||
u16 set_mask;
|
||||
u16 clr_mask;
|
||||
u8 default_resolution;
|
||||
u8 resolution_limits;
|
||||
const u8 *resolutions;
|
||||
unsigned int default_sample_time;
|
||||
u8 num_sample_times;
|
||||
const unsigned int *sample_times;
|
||||
bool alarm;
|
||||
};
|
||||
|
||||
/* Addresses scanned */
|
||||
@ -103,8 +109,8 @@ struct lm75_data {
|
||||
struct i2c_client *client;
|
||||
struct regmap *regmap;
|
||||
struct regulator *vs;
|
||||
u8 orig_conf;
|
||||
u8 current_conf;
|
||||
u16 orig_conf;
|
||||
u16 current_conf;
|
||||
u8 resolution; /* In bits, 9 to 16 */
|
||||
unsigned int sample_time; /* In ms */
|
||||
enum lm75_type kind;
|
||||
@ -127,6 +133,15 @@ static const struct lm75_params device_params[] = {
|
||||
.default_resolution = 12,
|
||||
.default_sample_time = MSEC_PER_SEC / 10,
|
||||
},
|
||||
[as6200] = {
|
||||
.config_reg_16bits = true,
|
||||
.set_mask = 0x94C0, /* 8 sample/s, 4 CF, positive polarity */
|
||||
.default_resolution = 12,
|
||||
.default_sample_time = 125,
|
||||
.num_sample_times = 4,
|
||||
.sample_times = (unsigned int []){ 125, 250, 1000, 4000 },
|
||||
.alarm = true,
|
||||
},
|
||||
[at30ts74] = {
|
||||
.set_mask = 3 << 5, /* 12-bit mode*/
|
||||
.default_resolution = 12,
|
||||
@ -316,20 +331,23 @@ static inline long lm75_reg_to_mc(s16 temp, u8 resolution)
|
||||
return ((temp >> (16 - resolution)) * 1000) >> (resolution - 8);
|
||||
}
|
||||
|
||||
static int lm75_write_config(struct lm75_data *data, u8 set_mask,
|
||||
u8 clr_mask)
|
||||
static int lm75_write_config(struct lm75_data *data, u16 set_mask,
|
||||
u16 clr_mask)
|
||||
{
|
||||
u8 value;
|
||||
unsigned int value;
|
||||
|
||||
clr_mask |= LM75_SHUTDOWN;
|
||||
clr_mask |= LM75_SHUTDOWN << (8 * data->params->config_reg_16bits);
|
||||
value = data->current_conf & ~clr_mask;
|
||||
value |= set_mask;
|
||||
|
||||
if (data->current_conf != value) {
|
||||
s32 err;
|
||||
|
||||
err = i2c_smbus_write_byte_data(data->client, LM75_REG_CONF,
|
||||
value);
|
||||
if (data->params->config_reg_16bits)
|
||||
err = regmap_write(data->regmap, LM75_REG_CONF, value);
|
||||
else
|
||||
err = i2c_smbus_write_byte_data(data->client,
|
||||
LM75_REG_CONF,
|
||||
value);
|
||||
if (err)
|
||||
return err;
|
||||
data->current_conf = value;
|
||||
@ -337,6 +355,27 @@ static int lm75_write_config(struct lm75_data *data, u8 set_mask,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lm75_read_config(struct lm75_data *data)
|
||||
{
|
||||
int ret;
|
||||
unsigned int status;
|
||||
|
||||
if (data->params->config_reg_16bits) {
|
||||
ret = regmap_read(data->regmap, LM75_REG_CONF, &status);
|
||||
return ret ? ret : status;
|
||||
}
|
||||
|
||||
return i2c_smbus_read_byte_data(data->client, LM75_REG_CONF);
|
||||
}
|
||||
|
||||
static irqreturn_t lm75_alarm_handler(int irq, void *private)
|
||||
{
|
||||
struct device *hwmon_dev = private;
|
||||
|
||||
hwmon_notify_event(hwmon_dev, hwmon_temp, hwmon_temp_alarm, 0);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int lm75_read(struct device *dev, enum hwmon_sensor_types type,
|
||||
u32 attr, int channel, long *val)
|
||||
{
|
||||
@ -365,6 +404,9 @@ static int lm75_read(struct device *dev, enum hwmon_sensor_types type,
|
||||
case hwmon_temp_max_hyst:
|
||||
reg = LM75_REG_HYST;
|
||||
break;
|
||||
case hwmon_temp_alarm:
|
||||
reg = LM75_REG_CONF;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -372,7 +414,17 @@ static int lm75_read(struct device *dev, enum hwmon_sensor_types type,
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
*val = lm75_reg_to_mc(regval, data->resolution);
|
||||
if (attr == hwmon_temp_alarm) {
|
||||
switch (data->kind) {
|
||||
case as6200:
|
||||
*val = (regval >> 5) & 0x1;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
} else {
|
||||
*val = lm75_reg_to_mc(regval, data->resolution);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
@ -435,6 +487,7 @@ static int lm75_update_interval(struct device *dev, long val)
|
||||
data->resolution = data->params->resolutions[index];
|
||||
break;
|
||||
case tmp112:
|
||||
case as6200:
|
||||
err = regmap_read(data->regmap, LM75_REG_CONF, ®);
|
||||
if (err < 0)
|
||||
return err;
|
||||
@ -502,6 +555,10 @@ static umode_t lm75_is_visible(const void *data, enum hwmon_sensor_types type,
|
||||
case hwmon_temp_max:
|
||||
case hwmon_temp_max_hyst:
|
||||
return 0644;
|
||||
case hwmon_temp_alarm:
|
||||
if (config_data->params->alarm)
|
||||
return 0444;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -514,7 +571,8 @@ static const struct hwmon_channel_info * const lm75_info[] = {
|
||||
HWMON_CHANNEL_INFO(chip,
|
||||
HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL),
|
||||
HWMON_CHANNEL_INFO(temp,
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST),
|
||||
HWMON_T_INPUT | HWMON_T_MAX | HWMON_T_MAX_HYST |
|
||||
HWMON_T_ALARM),
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -622,7 +680,7 @@ static int lm75_probe(struct i2c_client *client)
|
||||
return err;
|
||||
|
||||
/* Cache original configuration */
|
||||
status = i2c_smbus_read_byte_data(client, LM75_REG_CONF);
|
||||
status = lm75_read_config(data);
|
||||
if (status < 0) {
|
||||
dev_dbg(dev, "Can't read config? %d\n", status);
|
||||
return status;
|
||||
@ -645,6 +703,23 @@ static int lm75_probe(struct i2c_client *client)
|
||||
if (IS_ERR(hwmon_dev))
|
||||
return PTR_ERR(hwmon_dev);
|
||||
|
||||
if (client->irq) {
|
||||
if (data->params->alarm) {
|
||||
err = devm_request_threaded_irq(dev,
|
||||
client->irq,
|
||||
NULL,
|
||||
&lm75_alarm_handler,
|
||||
IRQF_ONESHOT,
|
||||
client->name,
|
||||
hwmon_dev);
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
/* alarm is only supported for chips with alarm bit */
|
||||
dev_err(dev, "alarm interrupt is not supported\n");
|
||||
}
|
||||
}
|
||||
|
||||
dev_info(dev, "%s: sensor '%s'\n", dev_name(hwmon_dev), client->name);
|
||||
|
||||
return 0;
|
||||
@ -652,6 +727,7 @@ static int lm75_probe(struct i2c_client *client)
|
||||
|
||||
static const struct i2c_device_id lm75_ids[] = {
|
||||
{ "adt75", adt75, },
|
||||
{ "as6200", as6200, },
|
||||
{ "at30ts74", at30ts74, },
|
||||
{ "ds1775", ds1775, },
|
||||
{ "ds75", ds75, },
|
||||
@ -688,6 +764,10 @@ static const struct of_device_id __maybe_unused lm75_of_match[] = {
|
||||
.compatible = "adi,adt75",
|
||||
.data = (void *)adt75
|
||||
},
|
||||
{
|
||||
.compatible = "ams,as6200",
|
||||
.data = (void *)as6200
|
||||
},
|
||||
{
|
||||
.compatible = "atmel,at30ts74",
|
||||
.data = (void *)at30ts74
|
||||
|
Loading…
Reference in New Issue
Block a user