mirror of
https://github.com/torvalds/linux.git
synced 2024-11-21 19:41:42 +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
|
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>
|
Author: Frodo Looijaard <frodol@dds.nl>
|
||||||
|
|
||||||
Description
|
Description
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/jiffies.h>
|
#include <linux/jiffies.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
@ -24,6 +25,7 @@
|
|||||||
|
|
||||||
enum lm75_type { /* keep sorted in alphabetical order */
|
enum lm75_type { /* keep sorted in alphabetical order */
|
||||||
adt75,
|
adt75,
|
||||||
|
as6200,
|
||||||
at30ts74,
|
at30ts74,
|
||||||
ds1775,
|
ds1775,
|
||||||
ds75,
|
ds75,
|
||||||
@ -54,6 +56,7 @@ enum lm75_type { /* keep sorted in alphabetical order */
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* struct lm75_params - lm75 configuration parameters.
|
* 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
|
* @set_mask: Bits to set in configuration register when configuring
|
||||||
* the chip.
|
* the chip.
|
||||||
* @clr_mask: Bits to clear in configuration register when configuring
|
* @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
|
* @sample_times: All the possible sample times to be set. Mandatory if
|
||||||
* num_sample_times is larger than 1. If set, number of
|
* num_sample_times is larger than 1. If set, number of
|
||||||
* entries must match num_sample_times.
|
* entries must match num_sample_times.
|
||||||
|
* @alarm: Alarm bit is supported.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct lm75_params {
|
struct lm75_params {
|
||||||
u8 set_mask;
|
bool config_reg_16bits;
|
||||||
u8 clr_mask;
|
u16 set_mask;
|
||||||
|
u16 clr_mask;
|
||||||
u8 default_resolution;
|
u8 default_resolution;
|
||||||
u8 resolution_limits;
|
u8 resolution_limits;
|
||||||
const u8 *resolutions;
|
const u8 *resolutions;
|
||||||
unsigned int default_sample_time;
|
unsigned int default_sample_time;
|
||||||
u8 num_sample_times;
|
u8 num_sample_times;
|
||||||
const unsigned int *sample_times;
|
const unsigned int *sample_times;
|
||||||
|
bool alarm;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Addresses scanned */
|
/* Addresses scanned */
|
||||||
@ -103,8 +109,8 @@ struct lm75_data {
|
|||||||
struct i2c_client *client;
|
struct i2c_client *client;
|
||||||
struct regmap *regmap;
|
struct regmap *regmap;
|
||||||
struct regulator *vs;
|
struct regulator *vs;
|
||||||
u8 orig_conf;
|
u16 orig_conf;
|
||||||
u8 current_conf;
|
u16 current_conf;
|
||||||
u8 resolution; /* In bits, 9 to 16 */
|
u8 resolution; /* In bits, 9 to 16 */
|
||||||
unsigned int sample_time; /* In ms */
|
unsigned int sample_time; /* In ms */
|
||||||
enum lm75_type kind;
|
enum lm75_type kind;
|
||||||
@ -127,6 +133,15 @@ static const struct lm75_params device_params[] = {
|
|||||||
.default_resolution = 12,
|
.default_resolution = 12,
|
||||||
.default_sample_time = MSEC_PER_SEC / 10,
|
.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] = {
|
[at30ts74] = {
|
||||||
.set_mask = 3 << 5, /* 12-bit mode*/
|
.set_mask = 3 << 5, /* 12-bit mode*/
|
||||||
.default_resolution = 12,
|
.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);
|
return ((temp >> (16 - resolution)) * 1000) >> (resolution - 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lm75_write_config(struct lm75_data *data, u8 set_mask,
|
static int lm75_write_config(struct lm75_data *data, u16 set_mask,
|
||||||
u8 clr_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 = data->current_conf & ~clr_mask;
|
||||||
value |= set_mask;
|
value |= set_mask;
|
||||||
|
|
||||||
if (data->current_conf != value) {
|
if (data->current_conf != value) {
|
||||||
s32 err;
|
s32 err;
|
||||||
|
if (data->params->config_reg_16bits)
|
||||||
err = i2c_smbus_write_byte_data(data->client, LM75_REG_CONF,
|
err = regmap_write(data->regmap, LM75_REG_CONF, value);
|
||||||
value);
|
else
|
||||||
|
err = i2c_smbus_write_byte_data(data->client,
|
||||||
|
LM75_REG_CONF,
|
||||||
|
value);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
data->current_conf = value;
|
data->current_conf = value;
|
||||||
@ -337,6 +355,27 @@ static int lm75_write_config(struct lm75_data *data, u8 set_mask,
|
|||||||
return 0;
|
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,
|
static int lm75_read(struct device *dev, enum hwmon_sensor_types type,
|
||||||
u32 attr, int channel, long *val)
|
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:
|
case hwmon_temp_max_hyst:
|
||||||
reg = LM75_REG_HYST;
|
reg = LM75_REG_HYST;
|
||||||
break;
|
break;
|
||||||
|
case hwmon_temp_alarm:
|
||||||
|
reg = LM75_REG_CONF;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
@ -372,7 +414,17 @@ static int lm75_read(struct device *dev, enum hwmon_sensor_types type,
|
|||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -435,6 +487,7 @@ static int lm75_update_interval(struct device *dev, long val)
|
|||||||
data->resolution = data->params->resolutions[index];
|
data->resolution = data->params->resolutions[index];
|
||||||
break;
|
break;
|
||||||
case tmp112:
|
case tmp112:
|
||||||
|
case as6200:
|
||||||
err = regmap_read(data->regmap, LM75_REG_CONF, ®);
|
err = regmap_read(data->regmap, LM75_REG_CONF, ®);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
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:
|
||||||
case hwmon_temp_max_hyst:
|
case hwmon_temp_max_hyst:
|
||||||
return 0644;
|
return 0644;
|
||||||
|
case hwmon_temp_alarm:
|
||||||
|
if (config_data->params->alarm)
|
||||||
|
return 0444;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -514,7 +571,8 @@ static const struct hwmon_channel_info * const lm75_info[] = {
|
|||||||
HWMON_CHANNEL_INFO(chip,
|
HWMON_CHANNEL_INFO(chip,
|
||||||
HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL),
|
HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL),
|
||||||
HWMON_CHANNEL_INFO(temp,
|
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
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -622,7 +680,7 @@ static int lm75_probe(struct i2c_client *client)
|
|||||||
return err;
|
return err;
|
||||||
|
|
||||||
/* Cache original configuration */
|
/* Cache original configuration */
|
||||||
status = i2c_smbus_read_byte_data(client, LM75_REG_CONF);
|
status = lm75_read_config(data);
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
dev_dbg(dev, "Can't read config? %d\n", status);
|
dev_dbg(dev, "Can't read config? %d\n", status);
|
||||||
return status;
|
return status;
|
||||||
@ -645,6 +703,23 @@ static int lm75_probe(struct i2c_client *client)
|
|||||||
if (IS_ERR(hwmon_dev))
|
if (IS_ERR(hwmon_dev))
|
||||||
return PTR_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);
|
dev_info(dev, "%s: sensor '%s'\n", dev_name(hwmon_dev), client->name);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -652,6 +727,7 @@ static int lm75_probe(struct i2c_client *client)
|
|||||||
|
|
||||||
static const struct i2c_device_id lm75_ids[] = {
|
static const struct i2c_device_id lm75_ids[] = {
|
||||||
{ "adt75", adt75, },
|
{ "adt75", adt75, },
|
||||||
|
{ "as6200", as6200, },
|
||||||
{ "at30ts74", at30ts74, },
|
{ "at30ts74", at30ts74, },
|
||||||
{ "ds1775", ds1775, },
|
{ "ds1775", ds1775, },
|
||||||
{ "ds75", ds75, },
|
{ "ds75", ds75, },
|
||||||
@ -688,6 +764,10 @@ static const struct of_device_id __maybe_unused lm75_of_match[] = {
|
|||||||
.compatible = "adi,adt75",
|
.compatible = "adi,adt75",
|
||||||
.data = (void *)adt75
|
.data = (void *)adt75
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.compatible = "ams,as6200",
|
||||||
|
.data = (void *)as6200
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.compatible = "atmel,at30ts74",
|
.compatible = "atmel,at30ts74",
|
||||||
.data = (void *)at30ts74
|
.data = (void *)at30ts74
|
||||||
|
Loading…
Reference in New Issue
Block a user