18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * AD7314 digital temperature sensor driver for AD7314, ADT7301 and ADT7302 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2010 Analog Devices Inc. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Conversion to hwmon from IIO done by Jonathan Cameron <jic23@cam.ac.uk> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci#include <linux/device.h> 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include <linux/sysfs.h> 138c2ecf20Sopenharmony_ci#include <linux/spi/spi.h> 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/err.h> 168c2ecf20Sopenharmony_ci#include <linux/hwmon.h> 178c2ecf20Sopenharmony_ci#include <linux/hwmon-sysfs.h> 188c2ecf20Sopenharmony_ci#include <linux/bitops.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/* 218c2ecf20Sopenharmony_ci * AD7314 temperature masks 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_ci#define AD7314_TEMP_MASK 0x7FE0 248c2ecf20Sopenharmony_ci#define AD7314_TEMP_SHIFT 5 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* 278c2ecf20Sopenharmony_ci * ADT7301 and ADT7302 temperature masks 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_ci#define ADT7301_TEMP_MASK 0x3FFF 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cienum ad7314_variant { 328c2ecf20Sopenharmony_ci adt7301, 338c2ecf20Sopenharmony_ci adt7302, 348c2ecf20Sopenharmony_ci ad7314, 358c2ecf20Sopenharmony_ci}; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistruct ad7314_data { 388c2ecf20Sopenharmony_ci struct spi_device *spi_dev; 398c2ecf20Sopenharmony_ci u16 rx ____cacheline_aligned; 408c2ecf20Sopenharmony_ci}; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic int ad7314_spi_read(struct ad7314_data *chip) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci int ret; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci ret = spi_read(chip->spi_dev, (u8 *)&chip->rx, sizeof(chip->rx)); 478c2ecf20Sopenharmony_ci if (ret < 0) { 488c2ecf20Sopenharmony_ci dev_err(&chip->spi_dev->dev, "SPI read error\n"); 498c2ecf20Sopenharmony_ci return ret; 508c2ecf20Sopenharmony_ci } 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci return be16_to_cpu(chip->rx); 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistatic ssize_t ad7314_temperature_show(struct device *dev, 568c2ecf20Sopenharmony_ci struct device_attribute *attr, 578c2ecf20Sopenharmony_ci char *buf) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci struct ad7314_data *chip = dev_get_drvdata(dev); 608c2ecf20Sopenharmony_ci s16 data; 618c2ecf20Sopenharmony_ci int ret; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci ret = ad7314_spi_read(chip); 648c2ecf20Sopenharmony_ci if (ret < 0) 658c2ecf20Sopenharmony_ci return ret; 668c2ecf20Sopenharmony_ci switch (spi_get_device_id(chip->spi_dev)->driver_data) { 678c2ecf20Sopenharmony_ci case ad7314: 688c2ecf20Sopenharmony_ci data = (ret & AD7314_TEMP_MASK) >> AD7314_TEMP_SHIFT; 698c2ecf20Sopenharmony_ci data = sign_extend32(data, 9); 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", 250 * data); 728c2ecf20Sopenharmony_ci case adt7301: 738c2ecf20Sopenharmony_ci case adt7302: 748c2ecf20Sopenharmony_ci /* 758c2ecf20Sopenharmony_ci * Documented as a 13 bit twos complement register 768c2ecf20Sopenharmony_ci * with a sign bit - which is a 14 bit 2's complement 778c2ecf20Sopenharmony_ci * register. 1lsb - 31.25 milli degrees centigrade 788c2ecf20Sopenharmony_ci */ 798c2ecf20Sopenharmony_ci data = ret & ADT7301_TEMP_MASK; 808c2ecf20Sopenharmony_ci data = sign_extend32(data, 13); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci return sprintf(buf, "%d\n", 838c2ecf20Sopenharmony_ci DIV_ROUND_CLOSEST(data * 3125, 100)); 848c2ecf20Sopenharmony_ci default: 858c2ecf20Sopenharmony_ci return -EINVAL; 868c2ecf20Sopenharmony_ci } 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic SENSOR_DEVICE_ATTR_RO(temp1_input, ad7314_temperature, 0); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic struct attribute *ad7314_attrs[] = { 928c2ecf20Sopenharmony_ci &sensor_dev_attr_temp1_input.dev_attr.attr, 938c2ecf20Sopenharmony_ci NULL, 948c2ecf20Sopenharmony_ci}; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ciATTRIBUTE_GROUPS(ad7314); 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic int ad7314_probe(struct spi_device *spi_dev) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci struct ad7314_data *chip; 1018c2ecf20Sopenharmony_ci struct device *hwmon_dev; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci chip = devm_kzalloc(&spi_dev->dev, sizeof(*chip), GFP_KERNEL); 1048c2ecf20Sopenharmony_ci if (chip == NULL) 1058c2ecf20Sopenharmony_ci return -ENOMEM; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci chip->spi_dev = spi_dev; 1088c2ecf20Sopenharmony_ci hwmon_dev = devm_hwmon_device_register_with_groups(&spi_dev->dev, 1098c2ecf20Sopenharmony_ci spi_dev->modalias, 1108c2ecf20Sopenharmony_ci chip, ad7314_groups); 1118c2ecf20Sopenharmony_ci return PTR_ERR_OR_ZERO(hwmon_dev); 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic const struct spi_device_id ad7314_id[] = { 1158c2ecf20Sopenharmony_ci { "adt7301", adt7301 }, 1168c2ecf20Sopenharmony_ci { "adt7302", adt7302 }, 1178c2ecf20Sopenharmony_ci { "ad7314", ad7314 }, 1188c2ecf20Sopenharmony_ci { } 1198c2ecf20Sopenharmony_ci}; 1208c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(spi, ad7314_id); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic struct spi_driver ad7314_driver = { 1238c2ecf20Sopenharmony_ci .driver = { 1248c2ecf20Sopenharmony_ci .name = "ad7314", 1258c2ecf20Sopenharmony_ci }, 1268c2ecf20Sopenharmony_ci .probe = ad7314_probe, 1278c2ecf20Sopenharmony_ci .id_table = ad7314_id, 1288c2ecf20Sopenharmony_ci}; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cimodule_spi_driver(ad7314_driver); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ciMODULE_AUTHOR("Sonic Zhang <sonic.zhang@analog.com>"); 1338c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Analog Devices AD7314, ADT7301 and ADT7302 digital temperature sensor driver"); 1348c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 135