一.SD5075芯片简介
SD5075 是一款高准确度温度传感器芯片内含高精度测温 ADC,在-40C ~+100°C 范围内典型误差小于+0.5°C,在-55C~+125°C 范围内典型误差小于士1.0°C。通过两线 IC/SMBus接口可以很方便与其他设备建立通信。设置 A2~A0 的地址线,可支持8 片芯片并联总线连接
本芯片可选 3 种工作模式: 连续测温模式单次测温模式,关断模式。可根据速度或功耗的需求灵活选择和配置。
管脚描述:
二.SD5075温度检测原理
原理:
SD5075芯片经过ALARM引脚检测温度的变化,经过模数转换器的转换,把温度值写入寄存器中,SOC再通过IIC读取寄存器的值,从而拿到温度值。
寄存器列表:
通过配置0x01寄存器为0x00,通过寄存器0x00读取到温度结果。
三.代码实现
#include <linux/miscdevice.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/notifier.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/compat.h>
#include <linux/printk.h>
#include <linux/kobject.h>
#include <linux/version.h>
#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x00)
#define DRIVER_NAME "IST_TEMP"
/*define logging*/
#define IST_TEMP_DEBUG 0
#if IST_TEMP_DEBUG
#define DBG(format, args...) \
printk(KERN_DEBUG "%s: " format, DRIVER_NAME, ##args)
#define ERR(format, args...) \
printk(KERN_ERR "%s: " format, DRIVER_NAME, ##args)
#define WARNING(format, args...) \
printk(KERN_WARN "%s: " format, DRIVER_NAME, ##args)
#define INFO(format, args...) \
printk(KERN_INFO "%s: " format, DRIVER_NAME, ##args)
#else
#define DBG(format, args...)
#define ERR(format, args...)
#define WARNING(format, args...)
#define INFO(format, args...)
#endif
struct temp_dev {
struct device *dev;
struct miscdevice miscdev;
struct i2c_client *client;
u32 value;
};
struct temp_dev *g_temp;
struct temp_dev *temp;
static int last_value = 0;//char
static void i2c_wr(struct temp_dev *temp, u16 reg, u8 *val, u32 n)
{
struct i2c_msg msg;
struct i2c_client *client = temp->client;
int err;
u8 data[128];
data[0] = reg;
memcpy(&data[1], val, n);
msg.addr = client->addr;
msg.flags = 0;
msg.buf = data;
msg.len = n + 1;
err = i2c_transfer(client->adapter, &msg, 1);
if (err != 1) {
ERR("%s: writing register 0x%x from 0x%x failed\n", __func__,
reg, client->addr);
} else {
switch (n) {
case 1:
INFO("I2C write 0x%02x = 0x%02x\n", reg, data[1]);
break;
case 2:
INFO("I2C write 0x%02x = 0x%02x%02x\n", reg, data[2],
data[1]);
break;
case 4:
INFO("I2C write 0x%02x = 0x%02x%02x%02x%02x\n", reg,
data[4], data[3], data[2], data[1]);
break;
default:
INFO("I2C write %d bytes from address 0x%02x\n", n,
reg);
}
}
}
static void i2c_rd(struct temp_dev *temp, u16 reg, u8 *val, u32 n)
{
struct i2c_msg msg[2];
struct i2c_client *client = temp->client;
int err;
u8 buf[1] = { reg };
/*msg[0] addr to read*/
msg[0].addr = client->addr;
msg[0].flags = 0;
msg[0].buf = buf;
msg[0].len = 1;
/*msg[1] read data*/
msg[1].addr = client->addr;
msg[1].flags = I2C_M_RD;
msg[1].buf = val;
msg[1].len = n;
err = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
if (err != ARRAY_SIZE(msg)) {
ERR("%s: reading register 0x%x from 0x%x failed\n", __func__,
reg, client->addr);
}
}
static void i2c_rd8(struct temp_dev *temp, u16 reg, u8 *val)
{
i2c_rd(temp, reg, val, 1);
}
static void i2c_wr8(struct temp_dev *temp, u16 reg, u8 buf)
{
i2c_wr(temp, reg, &buf, 1);
}
static void i2c_wr_word(struct temp_dev *temp, u16 reg, u16 val)
{
unsigned char data[2] = {0};
data[0] = (unsigned char)(val & 0xFF);
data[1] = (unsigned char)((val & 0xFF00) >> 8);
i2c_wr(temp, reg, data, 2);
}
static void i2c_rd_word(struct temp_dev *temp, u16 reg, u8 *val)
{
i2c_rd(temp, reg, val, 2);
}
static long temperature_ioctl(struct file *file, uint32_t cmd, unsigned long arg)
{
return 0;
}
static ssize_t temperature_write(struct file *file, const char __user *buf,
size_t size, loff_t *ppos)
{
return 1;
}
static ssize_t temperature_read(struct file *file, char __user *buf, size_t size,
loff_t *ppos)
{
return 1;
}
static ssize_t temperature_value_read(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct temp_dev *temp = g_temp;
int result = -1;
unsigned char reg;
unsigned char reg_value;
unsigned short value = 0;
unsigned char value1[2] = {0};
reg = 0x01;
reg_value = 0x00;
i2c_wr8(temp, reg, reg_value);
reg = 0x00;
i2c_rd_word(temp, reg, value1);
value = (value1[0]<<8|value1[1])>>4;
if(value >= 0x800)
{
printk(" temperature_value_read !!!");
value = (value - 2048)>>4;
result = value - 128;
}
else
{
result = value>>4;
printk(" temperature_value_read !!!");
}
if(result == -1)
{
result -= last_value;
printk(" temperature_value_read !!!");
if((result > 8) || (result < (-8)))
{
result = last_value;
}
else
{
result = -1;
}
}
temp->value = result;
return sprintf(buf, "%d\n", temp->value);
}
static ssize_t temperature_value_write(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
return count;
}
static DEVICE_ATTR(value, 0644,
temperature_value_read, temperature_value_write);
static void temp_init(struct temp_dev *temp)
{
}
static const struct file_operations temp_fops = {
.owner = THIS_MODULE,
.read = temperature_read,
.write = temperature_write,
.unlocked_ioctl = temperature_ioctl,
};
struct miscdevice temp_miscdev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "temp_dev",
.fops = &temp_fops,
};
static int temp_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct temp_dev *temp;
struct device *dev = &client->dev;
int ret;
dev_info(dev, " driver version: %02x.%02x.%02x",
DRIVER_VERSION >> 16,
(DRIVER_VERSION & 0xff00) >> 8,
DRIVER_VERSION & 0x00ff);
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -EIO;
DBG("chip found @ 0x%x (%s)\n", client->addr << 1,
client->adapter->name);
temp = devm_kzalloc(dev, sizeof(struct temp_dev), GFP_KERNEL);
if (!temp)
return -ENOMEM;
temp->client = client;
client->flags |= I2C_CLIENT_SCCB;
ret = misc_register(&temp_miscdev);
if (ret) {
ERR(" temp ERROR: could not register ist_temp device\n");
return ret;
}
ret = device_create_file(temp_miscdev.this_device,
&dev_attr_value);
if (ret) {
dev_err(temp->dev, " failed to create attr hdmirxsel!\n");
return ret;
}
temp_init(temp);
g_temp = temp;
INFO("%s found @ 0x%x (%s)\n", client->name, client->addr << 1,
client->adapter->name);
return 0;
}
static int temp_remove(struct i2c_client *client)
{
misc_deregister(&temp_miscdev);
kfree(temp);
return 0;
}
static const struct of_device_id temp_of_match[] = {
{ .compatible = "temperature" },
{}
};
MODULE_DEVICE_TABLE(of, temp_of_match);
static struct i2c_driver temp_driver = {
.probe = temp_probe,
.remove = temp_remove,
.driver = {
.owner = THIS_MODULE,
.name = DRIVER_NAME,
.of_match_table = of_match_ptr(temp_of_match),
},
};
static int __init temp_driver_init(void)
{
return i2c_add_driver(&temp_driver);
}
static void __exit temp_driver_exit(void)
{
i2c_del_driver(&ist_temp_driver);
}
device_initcall_sync(temp_driver_init);
module_exit(temp_driver_exit);
MODULE_DESCRIPTION("temperature sensor");
MODULE_AUTHOR("");
MODULE_LICENSE("GPL v2");